topical media & game development
#javascript-processing-example-topic-motion-circlecollision.htm / htm
<!DOCTYPE html>
<html><head>
<script src="javascript-processing-example-processing.js"></script>
<script src="javascript-processing-example-init.js"></script>
<link rel="stylesheet" href="javascript-processing-example-style.css">
</head><body><h1><a href="http://ejohn.org/blog/processingjs/">Processing.js</a></h1>
<h2>CircleCollision</h2>
<p>by Ira Greenberg.
Based on Keith Peter's Solution in
Foundation Actionscript Animation:
Making Things Move!
http://www.friendsofed.com/book.html?isbn=1590597915>
<p><a href="http://processing.org/learning/topics/circlecollision.html"><b>Original Processing.org Example:</b> CircleCollision</a><br>
<script type="application/processing">
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)
};
void setup(){
size(200, 200);
smooth();
noStroke();
}
void draw(){
background(51);
fill(204);
for (int i=0; i< 2; 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]);
}
checkObjectCollision(balls, vels);
}
void checkObjectCollision(Ball[] b, Vect2D[] v){
// 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;
// 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){
// 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
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] */
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;
/* 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);
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);
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;
// 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;
}
}
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;
}
}
</script><canvas width="200" height="200"></canvas></p>
<div style="overflow: hidden; height: 0px; width: 0px;"></div>
<pre><b>// All Examples Written by <a href="http://reas.com/">Casey Reas</a> and <a href="http://benfry.com/">Ben Fry</a>
// unless otherwise stated.</b>
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)
};
void setup(){
size(200, 200);
smooth();
noStroke();
}
void draw(){
background(51);
fill(204);
for (int i=0; i< 2; 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]);
}
checkObjectCollision(balls, vels);
}
void checkObjectCollision(Ball[] b, Vect2D[] v){
// 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;
// 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){
// 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
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] */
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;
/* 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);
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);
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;
// 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;
}
}
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;
}
}</pre>
</body></html>
(C) Æliens
20/2/2008
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.