We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexDiscussionExhibition › 2D Pool
Page Index Toggle Pages: 1
2D Pool (Read 679 times)
2D Pool
May 5th, 2008, 7:42am
 
An example of 2D pool

I have had to split this code into parts because of the post size limits

PART 1


Code:

// 2D Pool example

final int sw=320 , sh=240;

final float FRICTION
=
0.982;
final float BALL_MASS
=
160.0;
final float BALL_RADIUS
=
12.0;

float power=0.0;
int mx, my, ballcount;
boolean ballsmoving=false;
ballType[] ball = new ballType[30];

// MAIN setup
void setup(){
 size(sw,sh,JAVA2D);
 background(16,172,78);
 smooth();
 ellipseMode(CORNER);
 randomSeed(millis());
 frameRate(60);
 SetupCueBall();
 SetupTriangle();
}

class ballType{
 float x, y;    // position
 float dx, dy;  // x and y speeds
 float radius;  // radius of ball
 float mass;    // mass of ball
 int r,g,b;    // ball color
}
Re: 2D Pool
Reply #1 - May 5th, 2008, 7:43am
 

PART 2

Code:


// #############################################################

// MAIN LOOP
void draw(){
 background(60,140,80);
 UpdateBallPhysics();
 RenderBalls();
 // only if all balls are stationary
 if (ballsmoving==false){
   mx=mouseX ;  my=mouseY;
   DrawAimLine() ; DrawPowerBar();
   // power up and shoot
   if (mousePressed && (mouseButton == LEFT)) {
     power=power+0.3+(power*0.04);
     if (power > 50.0){
       power=50.0;
     }
   }else{
   int ang=angle(ball[0].x,ball[0].y,mx,my);
   ball[0].dx= sin(radians(ang)) * power;
   ball[0].dy=-cos(radians(ang)) * power;
   power=0;
   }
   // reset
   if (mousePressed && (mouseButton == RIGHT)) {
     ballcount=0;
     SetupCueBall() ;
     SetupTriangle();
   }
 }
}
 
void DrawAimLine(){
 stroke(200,200,200);
 line(ball[0].x,ball[0].y,mx,my);
 noFill();
 ellipse(mx-ball[0].radius, my-ball[0].radius, ball[0].radius*2, ball[0].radius*2);
 stroke(0);
}

void DrawPowerBar(){
 fill(0);
 rect(sw*0.3-1,sh-16,50*4+2,10);
 fill(color(170,251,206));
 rect(sw*0.3,sh-15,power*4,8);
 fill(color(200,200,200));
 //DrawText "[LMB] Shoot   [RMB] Reset    [Esc] Exit",10,10
}


// #############################################################

void SetupCueBall(){
 ball[0] = new ballType();
 ball[0].x = sw-BALL_RADIUS-24;
 ball[0].y = sh/2;
 ball[0].dx=0.0 ;
 ball[0].dy=0.0;
 ball[0].radius = BALL_RADIUS;
 ball[0].mass = BALL_MASS;
 ball[0].r=255 ;
 ball[0].g=255 ;
 ball[0].b=255;
}

void SetupTriangle(){
 final int ballTriangleSize=5;
 float ballrad2=BALL_RADIUS*2;
 ballcount=0;
 for(int xloop=ballTriangleSize;xloop>0;xloop--){
   for(int yloop=1;yloop<xloop+1;yloop++){
     ballcount++;
     ball[ballcount] = new ballType();
     ball[ballcount].radius = BALL_RADIUS;
     ball[ballcount].mass = BALL_MASS;
     ball[ballcount].x = (4-xloop)*ballrad2 + 100;
     ball[ballcount].y = (yloop*ballrad2) - (xloop*ballrad2)/2.0 + (sh/2);
     ball[ballcount].r= (int) random(255);
     ball[ballcount].g= (int) random(255);
     ball[ballcount].b= (int) random(255);
   }
 }
}


Re: 2D Pool
Reply #2 - May 5th, 2008, 7:44am
 
PART 3

Code:
void UpdateBallPhysics(){
// This is the main physics function for the
// balls. It contains the very basic movement
// physics as well as the collision response code
ballsmoving=false;
for (int i=0;i<ballcount;i++){
// check for any movements
if ((ball[i].dx!=0) || (ball[i].dy!=0)){
ballsmoving=true;
}
// update positions
ball[i].x+=ball[i].dx;
ball[i].y+=ball[i].dy;
// gradually slow down
ball[i].dx*=FRICTION;
ball[i].dy*=FRICTION;
// stop completely when below a certain speed
if (abs(ball[i].dx) < 0.068){
ball[i].dx=0;
}
if (abs(ball[i].dy) < 0.068){
ball[i].dy=0;
}
// COLLISION CHECKING
// Check each ball in the loop against
// every other (c against c2)
for(int i2=0;i2<ballcount;i2++){
float collisionDistance = ball[i].radius+ball[i2].radius;
float actualDistance = sqrt( pow(ball[i2].x-ball[i].x,2) + pow(ball[i2].y-ball[i].y,2) );
// collided or not?
if (actualDistance < collisionDistance){
float collNormalAngle = degrees(atan2(ball[i2].y-ball[i].y , ball[i2].x-ball[i].x));
// position exactly touching, no intersection
float moveDist1 = (collisionDistance-actualDistance)*(ball[i2].mass/(float)((ball[i].mass+ball[i2].mass)));
float moveDist2 = (collisionDistance-actualDistance)*(ball[i].mass/(float)((ball[i].mass+ball[i2].mass)));
ball[i].x=ball[i].x + moveDist1*cos(radians(collNormalAngle+180.0));
ball[i].y=ball[i].y + moveDist1*sin(radians(collNormalAngle+180.0));
ball[i2].x=ball[i2].x + moveDist2*cos(radians(collNormalAngle));
ball[i2].y=ball[i2].y + moveDist2*sin(radians(collNormalAngle));
// COLLISION RESPONSE
// n = vector connecting the centers of the balls.
// we are finding the components of the normalised vector n
float nX=cos(radians(collNormalAngle));
float nY=sin(radians(collNormalAngle));
// now find the length of the components of each movement vectors
// along n, by using dot product.
float a1 = ball[i].dx*nX + ball[i].dy*nY;
float a2 = ball[i2].dx*nX + ball[i2].dy*nY;
// optimisedP = 2(a1 - a2)
// ----------
// m1 + m2
float optimisedP = (2.0 * (a1-a2)) / (ball[i].mass + ball[i2].mass);
// now find out the resultant vectors
//// Local r1% = c1.v - optimisedP * mass2 * n
ball[i].dx = ball[i].dx - (optimisedP*ball[i2].mass*nX);
ball[i].dy = ball[i].dy - (optimisedP*ball[i2].mass*nY);
//// Local r2% = ball[i2].v - optimisedP * mass1 * n
ball[i2].dx = ball[i2].dx + (optimisedP*ball[i].mass*nX);
ball[i2].dy = ball[i2].dy + (optimisedP*ball[i].mass*nY);
}
}
// Simple bouncing off walls.
if (ball[i].x < ball[i].radius){
ball[i].x=ball[i].radius;
ball[i].dx=ball[i].dx*-0.9;
}
if (ball[i].x > width-ball[i].radius){
ball[i].x=width-ball[i].radius;
ball[i].dx=ball[i].dx*-0.9;
}
if (ball[i].y < ball[i].radius){
ball[i].y=ball[i].radius;
ball[i].dy=ball[i].dy*-0.9;
}
if (ball[i].y > height-ball[i].radius){
ball[i].y=height-ball[i].radius;
ball[i].dy=ball[i].dy*-0.9;
}
}
}

void RenderBalls(){
for(int i=0;i<ballcount;i++){
fill(color(ball[i].r,ball[i].g,ball[i].b));
ellipse(ball[i].x-ball[i].radius, ball[i].y-ball[i].radius, ball[i].radius*2, ball[i].radius*2);
}
}

int angle(float x1, float y1, float x2, float y2){
float a = atan2(x2-x1 , y2-y1);
a=180-degrees(a);
return (int) a;
}
Page Index Toggle Pages: 1