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 › Ball Collision
Page Index Toggle Pages: 1
Ball Collision (Read 5482 times)
Ball Collision
Jan 27th, 2008, 8:14pm
 
I've been having to figure out ball collision at work and I've got some basic progress thanks to this thread a work colleague pointed me to.

I've got a demo following but I've had to split it up into two because on the limit on post lengths.

Part 1:
Code:

// st33d's ball bashing demo
// Use cursor keys to smack the red ball into the others
BallParticle [] balls;
void setup(){
size(500, 500);
initBalls();
ellipseMode(CENTER);
smooth();
noStroke();
}
void draw(){
background(240, 200, 30);
updateBalls();
}
void initBalls(){
balls = new BallParticle[20];
for(int i=0; i<balls.length; i++)
balls[i] = new BallParticle(50+(i%5)*100, 100+(i/5)*100, 25);
balls[0].col = balls[0].init_col = color(255, 20, 20);
}
// Manage the balls here
void updateBalls(){
for(int i=0; i<balls.length; i++){
balls[i].verlet(0,0,0.97);
balls[i].col=lerpColor(balls[i].col, balls[i].init_col, 0.1);
}
for(int i=1; i<balls.length; i++){
for(int j=0; j<i; j++){
if(balls[i].intersects(balls[j])){
balls[i].col = balls[j].col = color(0);
resolveBallCollision(balls[i], balls[j]);
}
}
}
for(int i=0; i<balls.length; i++){
fill(balls[i].col);
ellipse(balls[i].x, balls[i].y, balls[i].radius*2, balls[i].radius*2);
}
if(keyPressed){
switch(keyCode){
case LEFT: balls[0].px += 1; break;
case RIGHT: balls[0].px -= 1; break;
case UP: balls[0].py += 1; break;
case DOWN: balls[0].py -= 1; break;
}
if(key == ' ') initBalls();
}
}
// Our ball particle
class BallParticle extends Point{
int init_col, col;
float px,py,ix,iy,temp_x,temp_y;
float radius, elasticity = 1.0;
BallParticle(float x, float y, float radius){
super(x, y);
this.ix = px = temp_x = x;
this.iy = py = temp_y = y;
this.radius = radius;
elasticity = 0.3;
col = init_col = color(255);
}
// Movement by verlet integration - a personal preference
void verlet(float gravity_x, float gravity_y, float damping){
temp_x = x;
temp_y = y;
x += damping * (x - px) + gravity_x;
y += damping * (y - py) + gravity_y;
px = temp_x;
py = temp_y;
}
// Fast test for intersection - no sqrts here chum
boolean intersects(BallParticle o){
return (o.x-x)*(o.x-x)+(o.y-y)*(o.y-y) <= (radius+o.radius)*(radius+o.radius);
}
}
// A quick point class to make measuring lines easier
static class Point{
float x,y;
Point(float x, float y){
this.x = x;
this.y = y;
}
}
// Reusable line class I use for vector math
static class Line{
Point a, b;
float vx, vy, len, dx, dy, rx, ry, lx, ly;
Line(Point a, Point b){
this.a = a;
this.b = b;
updateLine();
}
void updateLine(){
vx = b.x - a.x;
vy = b.y - a.y;
// length of vector
len = sqrt(vx * vx + vy * vy);
// normalized unit-sized components
if (len > 0) {
dx = vx / len;
dy = vy / len;
} else {
dx = 0.0;
dy = 0.0;
}
// right hand normal
rx = -dy;
ry = dx;
// left hand normal
lx = dy;
ly = -dx;
}
}
Re: Ball Collision
Reply #1 - Jan 27th, 2008, 8:15pm
 
Part 2 - the collision resolver:

Code:

// Ball collision is a transcript of code from the following url:
// http://www.phy.ntnu.edu.tw/ntnujava/index.php?topic=4.msg15#msg15
// Resolve a collision between Balls
void resolveBallCollision(BallParticle a, BallParticle b){
// Save velocities
float avx = a.x-a.px;
float avy = a.y-a.py;
float bvx = b.x-b.px;
float bvy = b.y-b.py;
// get the current line between the balls
Line ball_to_ball = new Line(a, b);
// do we have to wind back time?
float penetration = a.radius+b.radius-ball_to_ball.len;
float time_of_collision = 0;
if(penetration > 0){
// take the speed of the overlap and use that as a measurement to reverse time
float a_velocity_towards = avx*ball_to_ball.dx+avy*ball_to_ball.dy;
float b_velocity_towards = bvx*ball_to_ball.dx+bvy*ball_to_ball.dy;
time_of_collision = penetration/(a_velocity_towards-b_velocity_towards);
a.x -= avx*time_of_collision;
a.y -= avy*time_of_collision;
b.x -= bvx*time_of_collision;
b.y -= bvy*time_of_collision;
// ball 2 ball needs to be updated for the reflection to work
ball_to_ball.updateLine();
}
// the balls need to be reflected along their trajectories
// velocity projections
float a_velocity_dot = avx*ball_to_ball.dx+avy*ball_to_ball.dy;
float a_perp_velocity_dot = -avx*ball_to_ball.dy+avy*ball_to_ball.dx;
float b_velocity_dot = bvx*ball_to_ball.dx+bvy*ball_to_ball.dy;
float b_perp_velocity_dot = -bvx*ball_to_ball.dy+bvy*ball_to_ball.dx;
// new velocity projections
float a_new_velocity_dot = a_velocity_dot+a.elasticity+(b_velocity_dot-a_velocity_dot);
float b_new_velocity_dot = b_velocity_dot+b.elasticity+(a_velocity_dot-b_velocity_dot);
// calculate new velocities
avx = a_new_velocity_dot*ball_to_ball.dx-a_perp_velocity_dot*ball_to_ball.dy;
avy = a_new_velocity_dot*ball_to_ball.dy+a_perp_velocity_dot*ball_to_ball.dx;
bvx = b_new_velocity_dot*ball_to_ball.dx-b_perp_velocity_dot*ball_to_ball.dy;
bvy = b_new_velocity_dot*ball_to_ball.dy+b_perp_velocity_dot*ball_to_ball.dx;
// do we have to wind forward time?
if(penetration > 0){
// wind forward time to avoid balls sticking
// I've found that ommiting this part generally adds stability -
// the balls become less logical so you're not surprised when they skip ahead
a.x += avx*time_of_collision;
a.y += avy*time_of_collision;
b.x += bvx*time_of_collision;
b.y += bvy*time_of_collision;
}
// apply new velocity
a.px = a.x-avx;
a.py = a.y-avy;
b.px = b.x-bvx;
b.py = b.y-bvy;
}


Yes I could post an applet, but I haven't got FTP set up on my new laptop yet so I'll bother at a later date.
Re: Ball Collision
Reply #2 - Apr 13th, 2009, 5:01am
 
Hi,

Do you know how to do the collision on lines that are created by the blob detection? I am at the point that I can make an outline of a person with a cam and I would like to create balls in the screen that collide with his outline.

greets
Esther
Re: Ball Collision
Reply #3 - Apr 13th, 2009, 5:18am
 
I haven't done line / ball collision. It's not an especially simple topic.

I suggest you look at Box2D

http://processing.org/discourse/yabb2/board_Exhibition_3Baction_display_3Bnum_1213240030.html

Polygon collision is pretty complicated and a library like Box2D would probably save you a lot of headache.
Re: Ball Collision
Reply #4 - Jul 21st, 2009, 12:02pm
 
Hi, i'm working with this class with TUIO protocol,  but I am not obtaining a collision of the small balls with the extremities of the window, as they were inside of a box.

some light?

(I will place the code in different Messages)

//Main:
import oscP5.*;
import netP5.*;
import TUIO.*;

TuioProcessing tuioClient;
BallParticle[] finger;
BallParticle[] balls;
OscP5 oscP5;
NetAddress netAddress;
OscMessage[] oscBall, oscFinger;


float cursor_size = 15;
float object_size = 60;
float table_size = 760;
float scale_factor = 1;
String ip = "127.0.0.1";
int port = 57120;
int nFingers = 100;

void setup()
{
 size( 640, 640 );
 frameRate( 30 );
 smooth();
 ellipseMode( CENTER );
 noStroke();
 noCursor();
 initBalls();
 finger = new BallParticle[nFingers];
 tuioClient  = new TuioProcessing(this);
 setupOSC();
}

void draw(){

 background( 255 ,200,00);
 callFingers();
 updateBalls();
}




Re: Ball Collision
Reply #5 - Jul 21st, 2009, 12:03pm
 
// called when an object is added to the scene
void addTuioObject(TuioObject tobj) {
 println("add object "+tobj.getSymbolID()+" ("+tobj.getSessionID()+") "+tobj.getX()+" "+tobj.getY()+" "+tobj.getAngle());
}

// called when an object is removed from the scene
void removeTuioObject(TuioObject tobj) {
 println("remove object "+tobj.getSymbolID()+" ("+tobj.getSessionID()+")");
}

// called when an object is moved
void updateTuioObject (TuioObject tobj) {
 println("update object "+tobj.getSymbolID()+" ("+tobj.getSessionID()+") "+tobj.getX()+" "+tobj.getY()+" "+tobj.getAngle()
         +" "+tobj.getMotionSpeed()+" "+tobj.getRotationSpeed()+" "+tobj.getMotionAccel()+" "+tobj.getRotationAccel());
}

// called when a cursor is added to the scene
void addTuioCursor(TuioCursor tcur) {
 println("add cursor "+tcur.getCursorID()+" ("+tcur.getSessionID()+ ") " +tcur.getX()+" "+tcur.getY());

  int id = tcur.getCursorID();
  int idS = int(tcur.getSessionID());
  float speed=tcur.getMotionSpeed();  
  float px = convertX(tcur.getY());
  float py = convertY(tcur.getX());
  finger[id]=new BallParticle(px,py,25);
  finger[id].col = finger[id].init_col = color(234,0,0);
  fill(finger[id].col);
  ellipse(finger[id].x, finger[id].y, finger[id].radius*2, finger[id].radius*2);


}

// called when a cursor is moved
void updateTuioCursor (TuioCursor tcur) {
 println("update cursor "+tcur.getCursorID()+" ("+tcur.getSessionID()+ ") " +tcur.getX()+" "+tcur.getY()
         +" "+tcur.getMotionSpeed()+" "+tcur.getMotionAccel());
}

// called when a cursor is removed from the scene
void removeTuioCursor(TuioCursor tcur) {
 println("remove cursor "+tcur.getCursorID()+" ("+tcur.getSessionID()+")");
 int id = tcur.getCursorID();
 int idS = int(tcur.getSessionID());
}

// called after each message bundle
// representing the end of an image frame
void refresh(TuioTime bundleTime) {
 redraw();
}

void callFingers(){
 Vector tuioCursorList = tuioClient.getTuioCursors();
 for (int i=0;i<tuioCursorList.size();i++) {
   TuioCursor tcur = (TuioCursor)tuioCursorList.elementAt(i);
   Vector pointList = tcur.getPath();
   if (pointList.size()>0) {
     int id=tcur.getCursorID();
     float px = convertX(tcur.getY());
     float py = convertY(tcur.getX());  
     float oscX = px/width;
     float oscY = py/height;  
     finger[id].x=px;
     finger[id].y=py;
     
     
     //appears in screen
     fill(finger[id].col);
     ellipse(finger[id].x, finger[id].y, finger[id].radius*2, finger[id].radius*2);
     
     //interaction with each ball
     for(int j=0; j<balls.length; j++){
       if(finger[id].intersects(balls[j])){
         finger[id].col = balls[j].col = color(0);
         resolveBallCollision(finger[id], balls[j]);
       }
     }
     
     // send OSC message
     oscFinger[id] = new OscMessage("/system/finger/"+id);
     oscFinger[id].add(new float[] {oscX, oscY});
     oscP5.send (oscFinger[id], netAddress);
   }
 }
}


float convertX(float x){
 return (1-x)*width;
}


float convertY(float y){
 return (1-y)*height;
}

void initBalls(){
 balls = new BallParticle[10];
 for(int i=0; i<balls.length; i++)
   balls[i] = new BallParticle(50+(i%5)*100, 100+(i/5)*100, 25);
}

void updateBalls(){
 for(int i=0; i<balls.length; i++){
   balls[i].verlet(0,0,0.97);
   balls[i].col=lerpColor(balls[i].col, balls[i].init_col, 0.1);
 }
 for(int i=1; i<balls.length; i++){
   for(int j=0; j<i; j++){
   if(balls[i].intersects(balls[j])){
     balls[i].col = balls[j].col = color(0);
     resolveBallCollision(balls[i], balls[j]);
   }
   constrainBalls(balls[i]);
 }
 }
 for(int i=0; i<balls.length; i++){
   fill(balls[i].col);
   //sendOSC
   
   oscBall[i] = new OscMessage("/system/sound/"+i);
   oscBall[i].add(new float[] {1-(balls[i].x/width), 1-(balls[i].y/height)});
   oscP5.send(oscBall[i], netAddress);
   ellipse(balls[i].x, balls[i].y, balls[i].radius*2, balls[i].radius*2);
 }
}

void setupOSC(){
 oscP5 = new OscP5(this, port);
 netAddress = new NetAddress(ip, port);
 oscBall = new OscMessage[balls.length];
 oscFinger = new OscMessage[nFingers];
}
Re: Ball Collision
Reply #6 - Jul 21st, 2009, 12:07pm
 

class BallParticle extends Point{
 int init_col, col;
 float px,py,ix,iy,temp_x,temp_y;
 float radius, elasticity = 1.0;
 BallParticle(float x, float y, float radius){
   super(x, y);
   this.ix = px = temp_x = x;
   this.iy = py = temp_y = y;
   this.radius = radius;
   elasticity = 0.3;
   col = init_col = color(255);
 }
 // Movement by verlet integration - a personal preference
 void verlet(float gravity_x, float gravity_y, float damping){
   temp_x = x;
   temp_y = y;
   x += damping * (x - px) + gravity_x;
   y += damping * (y - py) + gravity_y;
   px = temp_x;
   py = temp_y;
 }
 // Fast test for intersection - no sqrts here chum
 boolean intersects(BallParticle o){
   return (o.x-x)*(o.x-x)+(o.y-y)*(o.y-y) <= (radius+o.radius)*(radius+o.radius);
 }
}
// A quick point class to make measuring lines easier
static class Point{
 float x,y;
 Point(float x, float y){
   this.x = x;
   this.y = y;
 }
}
// Reusable line class I use for vector math
static class Line{
 Point a, b;
 float vx, vy, len, dx, dy, rx, ry, lx, ly;
 Line(Point a, Point b){
   this.a = a;
   this.b = b;
   updateLine();
 }
 void updateLine(){
   vx = b.x - a.x;
   vy = b.y - a.y;
   // length of vector
   len = sqrt(vx * vx + vy * vy);
   // normalized unit-sized components
   if (len > 0) {
   dx = vx / len;
   dy = vy / len;
   } else {
   dx = 0.0;
   dy = 0.0;
   }
   // right hand normal
   rx = -dy;
   ry = dx;
   // left hand normal
   lx = dy;
   ly = -dx;
 }
}
// Ball collision is a transcript of code from the following url:
// Resolve a collision between Balls
void resolveBallCollision(BallParticle a, BallParticle b){
 // Save velocities
 float avx = a.x-a.px;
 float avy = a.y-a.py;
 float bvx = b.x-b.px;
 float bvy = b.y-b.py;
 // get the current line between the balls
 Line ball_to_ball = new Line(a, b);
 // do we have to wind back time?
 float penetration = a.radius+b.radius-ball_to_ball.len;
 float time_of_collision = 0;
 if(penetration > 0){
   // take the speed of the overlap and use that as a measurement to reverse time
   float a_velocity_towards = avx*ball_to_ball.dx+avy*ball_to_ball.dy;
   float b_velocity_towards = bvx*ball_to_ball.dx+bvy*ball_to_ball.dy;
   time_of_collision = penetration/(a_velocity_towards-b_velocity_towards);
   a.x -= avx*time_of_collision;
   a.y -= avy*time_of_collision;
   b.x -= bvx*time_of_collision;
   b.y -= bvy*time_of_collision;
   // ball 2 ball needs to be updated for the reflection to work
   ball_to_ball.updateLine();
 }
 // the balls need to be reflected along their trajectories
 // velocity projections
 float a_velocity_dot = avx*ball_to_ball.dx+avy*ball_to_ball.dy;
 float a_perp_velocity_dot = -avx*ball_to_ball.dy+avy*ball_to_ball.dx;
 float b_velocity_dot = bvx*ball_to_ball.dx+bvy*ball_to_ball.dy;
 float b_perp_velocity_dot = -bvx*ball_to_ball.dy+bvy*ball_to_ball.dx;
 // new velocity projections
 float a_new_velocity_dot = a_velocity_dot+a.elasticity+(b_velocity_dot-a_velocity_dot);
 float b_new_velocity_dot = b_velocity_dot+b.elasticity+(a_velocity_dot-b_velocity_dot);
 // calculate new velocities
 avx = a_new_velocity_dot*ball_to_ball.dx-a_perp_velocity_dot*ball_to_ball.dy;
 avy = a_new_velocity_dot*ball_to_ball.dy+a_perp_velocity_dot*ball_to_ball.dx;
 bvx = b_new_velocity_dot*ball_to_ball.dx-b_perp_velocity_dot*ball_to_ball.dy;
 bvy = b_new_velocity_dot*ball_to_ball.dy+b_perp_velocity_dot*ball_to_ball.dx;
 // do we have to wind forward time?
 if(penetration > 0){
   // wind forward time to avoid balls sticking
   // I've found that ommiting this part generally adds stability -
   // the balls become less logical so you're not surprised when they skip ahead
   a.x += avx*time_of_collision;
   a.y += avy*time_of_collision;
   b.x += bvx*time_of_collision;
   b.y += bvy*time_of_collision;
 }
 // apply new velocity
 a.px = a.x-avx;
 a.py = a.y-avy;
 b.px = b.x-bvx;
 b.py = b.y-bvy;
}

//This is th PROBLEM!!!!!!!
// i desire constrain Balls in the window, like a box
void constrainBalls(BallParticle a){
 if (a.x + a.radius < 0 || a.x + a.radius >width){
   a.px = a.px*-1;
 }
 if (a.y - a.radius < 0 || a.x + a.radius >height){
   a.py = a.py*-1;
 }
}
   
Re: Ball Collision
Reply #7 - Jul 21st, 2009, 12:09pm
 
Ah, this program works with tbeta software, for a multitouch system
Re: Ball Collision
Reply #8 - Jul 21st, 2009, 12:18pm
 
That's lot of code, when you identified the problematic function. This section isn't really to ask questions about your own code.

Look at the function again. No consistency between the two tests against 0, wrong variable on the second test against upper limit.
Should be:
Code:
void constrainBalls(BallParticle a) {
if (a.x - a.radius < 0 || a.x + a.radius > width) {
  a.px *= -1;
}
if (a.y - a.radius < 0 || a.y + a.radius > height) {
  a.py *= -1;
}
}
Re: Ball Collision
Reply #9 - Jul 22nd, 2009, 1:29pm
 
it is really a great code, beyond the main code;
I placed things about TUIO communication between Processing/Tbeta,
and OSC communication between SuperCollider and Processing

The previous code :

Code:
void constrainBalls(BallParticle a) {
if (a.x - a.radius < 0 || a.x + a.radius > width) {
a.px *= -1;
}
if (a.y - a.radius < 0 || a.y + a.radius > height) {
a.py *= -1;
}
}


it did not function, really I do not understand where's the problem (although knowledge that it occurs inside the class Ball methods...)

Re: Ball Collision
Reply #10 - Jul 22nd, 2009, 1:30pm
 
great code not!!!!!
a lot of code!!!!

sorry for my bad english... Tongue
Re: Ball Collision
Reply #11 - Jul 23rd, 2009, 11:59am
 
@ esther
Ball line collision

Check this code it may help

homepage.ntlworld.com/ricardo.sanchez/processing/collision_detection_1/


Cheers
rS
Page Index Toggle Pages: 1