This is pretty hard. I wasn’t expecting many people to have time to get it right. Take a look at how complicated the bounce() method got.
Maybe you can find a simpler way!
final float DELTA_T = 0.15;
class Obstacle {
PVector location;
float length;
Obstacle(PVector location_, float length_) {
location = location_.copy();
length = length_;
}
void display() {
rectMode(CENTER);
fill(0);
rect(location.x, location.y, length, length);
}
}
class Bouncer {
PVector location;
PVector velocity;
float radius;
Bouncer(PVector location_, PVector velocity_, float radius_) {
location = location_.copy();
velocity = velocity_.copy();
radius = radius_;
}
void update() {
location.add(velocity.copy().mult(DELTA_T));
}
void display() {
ellipseMode(CENTER);
noFill();
stroke(0);
ellipse(location.x, location.y, 2 * radius, 2 * radius);
}
void checkEdges() {
if (location.x < radius) {
location.x = radius;
velocity.x *= -1;
}
if (location.x > width - radius) {
location.x = width - radius;
velocity.x *= -1;
}
if (location.y < radius) {
location.y = radius;
velocity.y *= -1;
}
if (location.y > height - radius) {
location.y = height - radius;
velocity.y *= -1;
}
}
void bounce(Obstacle obstacle) {
PVector obstacleLocation = obstacle.location;
float obstacleLength = obstacle.length;
// These aren't really distances -- they are coordinate differences -- they can be negative:
float distanceFromLeft = location.x + radius - (obstacleLocation.x - obstacleLength / 2);
float distanceFromRight = location.x - radius - (obstacleLocation.x + obstacleLength / 2);
float distanceFromTop = location.y + radius - (obstacleLocation.y - obstacleLength / 2);
float distanceFromBottom = location.y - radius - (obstacleLocation.y + obstacleLength / 2);
if (distanceFromLeft > 0 && distanceFromRight < 0 && distanceFromTop > 0 && distanceFromBottom < 0) {
// We have hit the obstacle!
// Which side have we hit?
// These really are distances:
float smallestLeftRightDistance = Float.min(abs(distanceFromLeft), abs(distanceFromRight));
float smallestTopBottomDistance = Float.min(abs(distanceFromTop), abs(distanceFromBottom));
if (smallestLeftRightDistance < smallestTopBottomDistance) {
if (abs(distanceFromLeft) < abs(distanceFromRight)) {
location.x -= distanceFromLeft;
} else {
location.x -= distanceFromRight;
}
velocity.x *= -1;
} else {
if (abs(distanceFromBottom) < abs(distanceFromTop)) {
location.y -= distanceFromBottom;
} else {
location.y -= distanceFromTop;
}
velocity.y *= -1;
}
}
}
}
Obstacle[] obstacles = new Obstacle[5];
Bouncer[] bouncers = new Bouncer[50];
void setup() {
size(800, 600);
for (int i = 0; i < obstacles.length; ++i) {
obstacles[i] = new Obstacle(new PVector(random(0, width), random(0, height)), random(25, 50));
}
for (int i = 0; i < bouncers.length; ++i) {
bouncers[i] = new Bouncer(new PVector(random(0, width), random(0, height)), new PVector(random(-20, 20), random(-20, 20)), random(5, 10));
}
}
void draw() {
background(255);
for (int i = 0; i < obstacles.length; ++i) {
obstacles[i].display();
}
for (int j = 0; j < bouncers.length; ++j) {
bouncers[j].update();
for (int i = 0; i < obstacles.length; ++i) {
bouncers[j].bounce(obstacles[i]);
}
bouncers[j].checkEdges();
bouncers[j].display();
}
}