From d3124e80bb42ef0351550076d9635feafb89bb56 Mon Sep 17 00:00:00 2001
From: Jay H CircleCollision
// All Examples Written by Casey Reas and Ben Fry // unless otherwise stated. +int width = 200; +int height = 200; +int nBalls = 5; -Ball[] balls = { - - new Ball(100, 400, 10), - - new Ball(700, 400, 40) - - }; - - - -Vect2D[] vels = { - - new Vect2D(2.15, -1.35), - - new Vect2D(-1.65, .42) - - }; - - +Ball[] balls = new Ball[nBalls]; +Vect2D[] vels = new Vect2D[nBalls]; void setup(){ - - size(200, 200); - + size(width, height); smooth(); - noStroke(); - + initBalls(); } - +void initBalls(){ + for (int i = 0; i < nBalls; i++) { + balls[i] = new Ball(30*i, 30*i, random(5, 15)); + vels[i] = new Vect2D(1, 1); + } +} void draw(){ - background(51); - fill(204); - - for (int i=0; i< 2; i++){ - + for (int i = 0; i < nBalls; i++){ balls[i].x += vels[i].vx; - balls[i].y += vels[i].vy; - ellipse(balls[i].x, balls[i].y, balls[i].r*2, balls[i].r*2); - checkBoundaryCollision(balls[i], vels[i]); - + // check all ball pairs for collisions + for (int j = i+1; j < nBalls; j++){ + checkObjectCollision(balls[i], vels[i], balls[j], vels[j]); + } } - - checkObjectCollision(balls, vels); - } - - -void checkObjectCollision(Ball[] b, Vect2D[] v){ - - +void checkObjectCollision(Ball b1, Vect2D v1, Ball b2, Vect2D v2){ // get distances between the balls components - Vect2D bVect = new Vect2D(); - - bVect.vx = b[1].x - b[0].x; - - bVect.vy = b[1].y - b[0].y; - - + bVect.vx = b2.x - b1.x; + bVect.vy = b2.y - b1.y; // calculate magnitude of the vector separating the balls - float bVectMag = sqrt(bVect.vx * bVect.vx + bVect.vy * bVect.vy); - - if (bVectMag < b[0].r + b[1].r){ - + if (bVectMag < b1.r + b2.r){ // get angle of bVect - float theta = atan2(bVect.vy, bVect.vx); - // precalculate trig values - float sine = sin(theta); - float cosine = cos(theta); - - /* bTemp will hold rotated ball positions. You - just need to worry about bTemp[1] position*/ - Ball[] bTemp = { - new Ball(), new Ball() }; - - /* b[1]'s position is relative to b[0]'s - + /* b2's position is relative to b1's so you can use the vector between them (bVect) as the - reference point in the rotation expressions. - bTemp[0].x and bTemp[0].y will initialize - automatically to 0.0, which is what you want - - since b[1] will rotate around b[0] */ - + since b2 will rotate around b1 */ bTemp[1].x = cosine * bVect.vx + sine * bVect.vy; - bTemp[1].y = cosine * bVect.vy - sine * bVect.vx; - - // rotate Temporary velocities - Vect2D[] vTemp = { - new Vect2D(), new Vect2D() }; - - vTemp[0].vx = cosine * v[0].vx + sine * v[0].vy; - - vTemp[0].vy = cosine * v[0].vy - sine * v[0].vx; - - vTemp[1].vx = cosine * v[1].vx + sine * v[1].vy; - - vTemp[1].vy = cosine * v[1].vy - sine * v[1].vx; - - + vTemp[0].vx = cosine * v1.vx + sine * v1.vy; + vTemp[0].vy = cosine * v1.vy - sine * v1.vx; + vTemp[1].vx = cosine * v2.vx + sine * v2.vy; + vTemp[1].vy = cosine * v2.vy - sine * v2.vx; /* Now that velocities are rotated, you can use 1D - conservation of momentum equations to calculate - the final velocity along the x-axis. */ - Vect2D[] vFinal = { - new Vect2D(), new Vect2D() }; - - // final rotated velocity for b[0] - - vFinal[0].vx = ((b[0].m - b[1].m) * vTemp[0].vx + 2 * b[1].m * - - vTemp[1].vx) / (b[0].m + b[1].m); - + // final rotated velocity for b1 + vFinal[0].vx = ((b1.m - b2.m) * vTemp[0].vx + 2 * b2.m * + vTemp[1].vx) / (b1.m + b2.m); vFinal[0].vy = vTemp[0].vy; - - // final rotated velocity for b[0] - - vFinal[1].vx = ((b[1].m - b[0].m) * vTemp[1].vx + 2 * b[0].m * - - vTemp[0].vx) / (b[0].m + b[1].m); - + // final rotated velocity for b1 + vFinal[1].vx = ((b2.m - b1.m) * vTemp[1].vx + 2 * b1.m * + vTemp[0].vx) / (b1.m + b2.m); vFinal[1].vy = vTemp[1].vy; - - // hack to avoid clumping - bTemp[0].x += vFinal[0].vx; - bTemp[1].x += vFinal[1].vx; - - /* Rotate ball positions and velocities back - Reverse signs in trig expressions to rotate - in the opposite direction */ - // rotate balls - Ball[] bFinal = { - new Ball(), new Ball() }; - 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; - - // update balls to screen position - - b[1].x = b[0].x + bFinal[1].x; - - b[1].y = b[0].y + bFinal[1].y; - - b[0].x = b[0].x + bFinal[0].x; - - b[0].y = b[0].y + bFinal[0].y; - - + b2.x = b1.x + bFinal[1].x; + b2.y = b1.y + bFinal[1].y; + b1.x = b1.x + bFinal[0].x; + b1.y = b1.y + bFinal[0].y; // update velocities - - v[0].vx = cosine * vFinal[0].vx - sine * vFinal[0].vy; - - v[0].vy = cosine * vFinal[0].vy + sine * vFinal[0].vx; - - v[1].vx = cosine * vFinal[1].vx - sine * vFinal[1].vy; - - v[1].vy = cosine * vFinal[1].vy + sine * vFinal[1].vx; - + v1.vx = cosine * vFinal[0].vx - sine * vFinal[0].vy; + v1.vy = cosine * vFinal[0].vy + sine * vFinal[0].vx; + v2.vx = cosine * vFinal[1].vx - sine * vFinal[1].vy; + v2.vy = cosine * vFinal[1].vy + sine * vFinal[1].vx; } - } - - class Ball{ - float x, y, r, m; - - // default constructor - Ball() { - } - - Ball(float x, float y, float r) { - this.x = x; - this.y = y; - this.r = r; - m = r*.1; - } - } - - class Vect2D{ - float vx, vy; - - // default constructor - Vect2D() { - } - - Vect2D(float vx, float vy) { - this.vx = vx; - this.vy = vy; - } - } - - // checkBoundaryCollision() function: - void checkBoundaryCollision(Ball ball, Vect2D vel){ - if (ball.x > width-ball.r){ - ball.x = width-ball.r; - vel.vx *= -1; - } - else if (ball.x < ball.r){ - ball.x = ball.r; - vel.vx *= -1; - } - else if (ball.y > height-ball.r){ - ball.y = height-ball.r; - vel.vy *= -1; - } - else if (ball.y < ball.r){ - ball.y = ball.r; - vel.vy *= -1; - } - -}