Skip to content

Instantly share code, notes, and snippets.

@Sam-Belliveau
Last active February 27, 2019 05:38
Show Gist options
  • Select an option

  • Save Sam-Belliveau/1f0065fa40caf119343d0ea8619caa16 to your computer and use it in GitHub Desktop.

Select an option

Save Sam-Belliveau/1f0065fa40caf119343d0ea8619caa16 to your computer and use it in GitHub Desktop.
static final float PROGRAM_SPEED = 0.1;
final int BALL_COUNT = 100;
final int MAX_SIZE = 25;
final int MIN_SIZE = 5;
Object[] ballList = new Object[BALL_COUNT];
void setup() {
size(1280, 720);
for(int i = 0; i < BALL_COUNT; ++i) {
float size = random(MIN_SIZE,MAX_SIZE);
PVector pos = new PVector(i*width/(float)BALL_COUNT, (i*MAX_SIZE*2)%height);
ballList[i] = new Object(pos, size);
ballList[i].vel.x = PROGRAM_SPEED*random(-5, 5);
}
}
void draw() {
for(int i = 0; i < BALL_COUNT; ++i) {
for(int j = i + 1; j < BALL_COUNT; ++j) {
ballList[i].bounce(ballList[j]);
}
}
clear();
for(int i = 0; i < BALL_COUNT; ++i) {
ballList[i].updatePos();
ballList[i].updateGravity(width, height);
ballList[i].drawObject();
}
}
class Object {
public static final float GRAVITY_VAL = 0.1*PROGRAM_SPEED;
public static final float BOUNCE_VAL = 1;
public static final boolean ROOF = false;
public PVector pos, vel;
public float size;
Object(PVector pos, float size) {
this.size = size;
this.pos = pos;
vel = new PVector(0,0);
}
public void drawObject() {
ellipse(pos.x, pos.y, size*2, size*2);
}
public void updatePos() {
pos.x += vel.x;
pos.y += vel.y;
}
public void updateGravity(float winWidth, float winHeight) {
vel.y += GRAVITY_VAL;
if(vel.y > 0 && pos.y + size >= winHeight) {
vel.y *= -BOUNCE_VAL;
pos.y = winHeight - size;
} else if(ROOF && vel.y < 0 && pos.y - size <= 0) {
vel.y *= -BOUNCE_VAL;
pos.y = size;
}
if(vel.x > 0 && pos.x + size >= winWidth) {
vel.x *= -BOUNCE_VAL;
pos.x = winWidth - size;
} else if(vel.x < 0 && pos.x - size <= 0) {
vel.x *= -BOUNCE_VAL;
pos.x = size;
}
}
public void bounce(Object other) {
if(isTouching(other)) {
// WARNING! STOLEN CODE
// PHYSICS IS COMPLICATED
// WE STOLE THIS!!!
float mass = size*size;
float otherMass = other.size*other.size;
PVector distanceVect = PVector.sub(other.pos, pos);
float distanceVectMag = distanceVect.mag();
float minDistance = size + other.size;
float distanceCorrection = (minDistance-distanceVectMag)/2.0;
PVector d = distanceVect.copy();
PVector correctionVector = d.normalize().mult(distanceCorrection);
other.pos.add(correctionVector);
pos.sub(correctionVector);
float theta = distanceVect.heading();
float sine = sin(theta);
float cosine = cos(theta);
PVector[] bTemp = { new PVector(), new PVector() };
PVector[] vTemp = { new PVector(), new PVector() };
bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y;
bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x;
vTemp[0].x = cosine * vel.x + sine * vel.y;
vTemp[0].y = cosine * vel.y - sine * vel.x;
vTemp[1].x = cosine * other.vel.x + sine * other.vel.y;
vTemp[1].y = cosine * other.vel.y - sine * other.vel.x;
PVector[] vFinal = { new PVector(), new PVector() };
PVector[] bFinal = { new PVector(), new PVector() };
vFinal[0].x = ((mass - otherMass) * vTemp[0].x + 2 * otherMass * vTemp[1].x) / (mass + otherMass);
vFinal[0].y = vTemp[0].y;
vFinal[1].x = ((otherMass - mass) * vTemp[1].x + 2 * mass * vTemp[0].x) / (mass + otherMass);
vFinal[1].y = vTemp[1].y;
bTemp[0].x += vFinal[0].x;
bTemp[1].x += vFinal[1].x;
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
other.pos.x = pos.x + bFinal[1].x;
other.pos.y = pos.y + bFinal[1].y;
pos.add(bFinal[0]);
vel.x = cosine * vFinal[0].x - sine * vFinal[0].y;
vel.y = cosine * vFinal[0].y + sine * vFinal[0].x;
other.vel.x = cosine * vFinal[1].x - sine * vFinal[1].y;
other.vel.y = cosine * vFinal[1].y + sine * vFinal[1].x;
}
}
public boolean isTouching(Object other) {
float distance = getDistance(pos, other.pos);
boolean touching = distance <= size + other.size;
// Prevent balls getting stuck
// TODO: Explain this part to newbies
// it took a lot of time to figure this part out
// so I did it in my free time.
boolean xCheck, yCheck;
if(pos.x < other.pos.x) xCheck = vel.x > other.vel.x;
else xCheck = vel.x < other.vel.x;
if(pos.y < other.pos.y) yCheck = vel.y > other.vel.y;
else yCheck = vel.y < other.vel.y;
return touching && (xCheck || yCheck);
}
private float getDistance(PVector a, PVector b) {
float xDis = a.x - b.x;
float yDis = a.y - b.y;
return (float)Math.sqrt(xDis*xDis + yDis*yDis);
}
}
@iwei20

iwei20 commented Feb 27, 2019

Copy link
Copy Markdown

epic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment