#### Howdy, Stranger!

We are about to switch to a new forum software. Until then we have removed the registration on this forum.

# Collision of 2 balls: How can I make sure only 1 collision is detected?

edited December 2013

Hello,

I am trying to get a simple collision of 2 balls to work. Unfortunately sometimes 2 collisions (1 from the point of view of each ball) are detected and the balls get stuck together. How can I make sure only 1 collision is detected?

Thank you in advance for your time and help. Here is the code.

Cecilia

``````int count;
int index;
float d;
Ball ball1;
Ball ball2;
float angleBetween1;
float angleBetween2;

float distanceAngle;
float velocityAngle1;
float velocityAngle2;
PVector distance;
boolean collision;

void setup() {
size(400, 400);
background(128);
frameRate(25);
collision = false;
ball1 = new Ball(20, 40);
ball2 = new Ball(200, 300);
d = 0;
distance = new PVector(0, 0);
}

void draw() {
background(128);
ball1.ballMove();
ball1.ballBounce();
ball1.ballDraw();
ball2.ballMove();
ball2.ballBounce();
ball2.ballDraw();

if (collision == false) {
PVector distance = PVector.sub(ball1.location, ball2.location);
d = distance.mag();
if (d <= ((ball1.getDiameter()/2)+(ball1.getDiameter()/2))) {
collision = true;
println("collision");
}
}
if (collision == true) {

distanceAngle = distance.heading();

velocityAngle1 = ball1.velocity.heading();
velocityAngle2 = ball1.velocity.heading();

angleBetween1 = PVector.angleBetween(distance, ball1.velocity);
angleBetween2 = PVector.angleBetween(distance, ball2.velocity);

if (velocityAngle1 > distanceAngle) {
ball1.velocity.rotate(-(velocityAngle1*2));
ball1.velocity.mult(-1);
}
if (velocityAngle1 < distanceAngle) {
ball1.velocity.rotate(velocityAngle1*2);
ball1.velocity.mult(-1);
}
if (velocityAngle2 > distanceAngle) {
ball2.velocity.rotate(-(velocityAngle2*2));
ball2.velocity.mult(-1);
}
if (velocityAngle2 < distanceAngle) {
ball2.velocity.rotate(velocityAngle2*2);
ball2.velocity.mult(-1);
}
collision = false;
}
}

class Ball {
PVector location;
PVector velocity;
float diameter;

Ball(float tempX, float tempY) {
diameter = random(100, 120);
location = new PVector(tempX,tempY);
velocity = new PVector(3, 3.1);
}

float getDiameter() {
return diameter;
}

void ballMove() {
location.add(velocity);
}

void ballBounce() {
if (location.x + diameter / 2 > width) {
location.x = width - diameter/2;
velocity.x = velocity.x *-1;
}
if (location.x - diameter / 2 < 0) {
location.x = 0 + diameter/2;
velocity.x = velocity.x *-1;
}
if (location.y + diameter / 2 > height) {
location.y = height - diameter/2;
velocity.y = velocity.y *-1;
}
if (location.y - diameter / 2 < 0) {
location.y = 0 + diameter/2;
velocity.y = velocity.y *-1;
}
}

void ballDraw() {
fill(200, 50);
noStroke();
ellipse(location.x, location.y, diameter, diameter);
}
}
``````
Tagged:

## Answers

• ``````velocityAngle1 = ball1.velocity.heading();
velocityAngle2 = ball1.velocity.heading();
``````

typo?

• Yes, this is a typo, thank you.

Unfortunately that doesn't stop the objects from getting stuck together. Any idea why that might be?

• could it be this typo? 8)

`if (d <= ((ball1.getDiameter()/2)+(ball1.getDiameter()/2))) {`

• ^ that might make it think balls have collided when they haven't, or have collided again when they were just starting to head off in different directions. would happen more if balls were quite different sizes.

• Thanks for spotting another typo. But unfortunately that doesn't fix the getting stuck together issue either.

Assuming that code for the actual bounce is okay (I am not certain, but let's assume), I think what happens is that a collision is detected and the code from line 45 is executed. But then in the next iteration of the draw method the balls are still overlapping. As a result another collision is detected and the code from line 45 onwards is executed. This means a reversal of direction again so the balls are overlapping even more. And then they are stuck. Do you think this could be the problem?

Thanks for your time and help.

• yes, i think that might be the problem

try adding visible vectors to the drawing so you can see where everything's going.

• those collisions look wrong.

i've added some debug - it stops when it collides. the green is the current velocity, the blue is the new velocity. press a key to restart it.

NB my version of processing doesn't have pvector.heading() so i've made my own, copied from pvector source.

``````int count;
int index;
float d;
Ball ball1;
Ball ball2;
float angleBetween1;
float angleBetween2;

float distanceAngle;
float velocityAngle1;
float velocityAngle2;
PVector distance;
boolean collision;

void setup() {
size(400, 400);
background(128);
frameRate(25);
collision = false;
ball1 = new Ball(20, 40);
ball2 = new Ball(200, 300);
d = 0;
distance = new PVector(0, 0);
}

void draw() {
background(128);
ball1.ballMove();
ball1.ballBounce();
ball1.ballDraw();
ball2.ballMove();
ball2.ballBounce();
ball2.ballDraw();

if (collision == false) {
PVector distance = PVector.sub(ball1.location, ball2.location);
d = distance.mag();
if (d <= ((ball1.getDiameter()/2)+(ball2.getDiameter()/2))) {
collision = true;
println("collision");
stroke(255, 0, 0);
line(ball1.location.x, ball1.location.y, ball2.location.x, ball2.location.y);
noLoop();
}
}
if (collision == true) {

distanceAngle = heading(distance);

velocityAngle1 = heading(ball1.velocity);
velocityAngle2 = heading(ball2.velocity);

angleBetween1 = PVector.angleBetween(distance, ball1.velocity);
angleBetween2 = PVector.angleBetween(distance, ball2.velocity);

// velocity before - green
stroke(0, 0, 255);
line(ball1.location.x, ball1.location.y, ball1.location.x + ball1.velocity.x * 10, ball1.location.y + ball1.velocity.y * 10);
line(ball2.location.x, ball2.location.y, ball2.location.x + ball2.velocity.x * 10, ball2.location.y + ball2.velocity.y * 10);

if (velocityAngle1 > distanceAngle) {
ball1.velocity.rotate(-(velocityAngle1*2));
ball1.velocity.mult(-1);
}
if (velocityAngle1 < distanceAngle) {
ball1.velocity.rotate(velocityAngle1*2);
ball1.velocity.mult(-1);
}
if (velocityAngle2 > distanceAngle) {
ball2.velocity.rotate(-(velocityAngle2*2));
ball2.velocity.mult(-1);
}
if (velocityAngle2 < distanceAngle) {
ball2.velocity.rotate(velocityAngle2*2);
ball2.velocity.mult(-1);
}
collision = false;

// velocity after = blue
stroke(0, 255, 0);
line(ball1.location.x, ball1.location.y, ball1.location.x + ball1.velocity.x * 10, ball1.location.y + ball1.velocity.y * 10);
line(ball2.location.x, ball2.location.y, ball2.location.x + ball2.velocity.x * 10, ball2.location.y + ball2.velocity.y * 10);
}
}

class Ball {
PVector location;
PVector velocity;
float diameter;

Ball(float tempX, float tempY) {
diameter = random(100, 120);
location = new PVector(tempX,tempY);
velocity = new PVector(3, 3.1);
}

float getDiameter() {
return diameter;
}

void ballMove() {
location.add(velocity);
}

void ballBounce() {
if (location.x + diameter / 2 > width) {
location.x = width - diameter/2;
velocity.x = velocity.x *-1;
}
if (location.x - diameter / 2 < 0) {
location.x = 0 + diameter/2;
velocity.x = velocity.x *-1;
}
if (location.y + diameter / 2 > height) {
location.y = height - diameter/2;
velocity.y = velocity.y *-1;
}
if (location.y - diameter / 2 < 0) {
location.y = 0 + diameter/2;
velocity.y = velocity.y *-1;
}
}

void ballDraw() {
fill(200, 50);
noStroke();
ellipse(location.x, location.y, diameter, diameter);
stroke(255);
line(location.x, location.y,location.x + velocity.x * 10, location.y + velocity.y * 10);
}
}

void keyPressed() {
loop();
}

// taken from pvector source
// http://processing.googlecode.com/svn/trunk/processing/core/src/processing/core/PVector.java
float heading(PVector p) {
float angle = (float) Math.atan2(-p.y, p.x);
return -1*angle;
}
``````
• Thank you very much. That does highlight lots of mistakes. I think the problem is that I tried to calculate it all with vectors. I think basic trigonometry is the way forward. Or can you see a way to calculate it with vectors?

• no, i think vectors will do what you need - they are only a class to make vector arithmetic easier and that's what you need.

resultant vector needs to be a reflection of the initial vector using the collision line as the mirror. which you can do with rotations. i think you may just be rotating one of the angles in the wrong direction. no obvious solution came to mind last night and i have other things to do so... it doesn't look THAT wrong tbh, like it's a sign issue or something.

• Thank you very much for your help. Making the vectors visible helps a lot. I will try to solve the problem, but unfortunately have got other things to do now too.

• hello, I'm new in this forum and a new Processing user. I didn't take the problem of the collision the same way you did it, especially because I'm not that confident with mathematics and the use of vector. Nevertheless, this is the way I treated the question and it seems to work. Sure, the rebound does not always look realistic. I just transfer Ball1 movement to Ball2 and vice versa. I think I probably would have to take in account the rotation of the ball... but it's a first approach and it works not so bad and I hope it could help.

Now I have a question: do anybody have an idea how to deal the same behavior with 100 balls ?

``````// position initiale du cercle et du cube
float circle_x = 300;
float circle_y = 20;
float cube_x = 50;
float cube_y = 150;
// déplacement à chaque frame
float move_x = 5.0;
float move_y = -7.1;
float moveCubeX = 1.2;
float moveCubeY = 1.7;
float tempx;
float tempy;
float RadCircle = 50;

void setup() {
size(400, 600);

}
void draw() {
background(#21EA73);
fill(255,0,0);
ellipse(circle_x, circle_y, RadCircle*2, RadCircle*2);
fill(0,0,255);
ellipse(cube_x, cube_y, RadCircle*2, RadCircle*2);
line(circle_x, circle_y,cube_x, cube_y);

circle_x = circle_x + move_x;
circle_y = circle_y + move_y;
cube_x = cube_x + moveCubeX;
cube_y = cube_y + moveCubeY;

// controle cube
if(cube_x + RadCircle > width) {
cube_x = width - RadCircle;
moveCubeX = -moveCubeX;
// cube too close right;
}
if(cube_y + RadCircle > height) {
cube_y = height - RadCircle;
moveCubeY = -moveCubeY;
//Cube too close bottom;
}
if(cube_x -RadCircle < 0) {
cube_x = RadCircle;
moveCubeX = -moveCubeX;
//Cube too close left;
}
if(cube_y -RadCircle < 0) {
cube_y = RadCircle;
moveCubeY = -moveCubeY;
//Cube too close top;
}

// control circle
if(circle_x + RadCircle > width) {
circle_x = width - RadCircle;
move_x = -move_x;
//too far right
}
if(circle_y + RadCircle > height) {
circle_y = height - RadCircle;
move_y = -move_y;
//too far bottom
}
if(circle_x - RadCircle < 0) {
circle_x = RadCircle;
move_x = -move_x;
//too far left
}
if(circle_y - RadCircle < 0) {
circle_y = RadCircle;
move_y = -move_y;
//too far top
}

// controle collision

if (sqrt((circle_x - cube_x )*(circle_x - cube_x ) + (circle_y - cube_y)*(circle_y - cube_y))<= RadCircle*2) {

println("Collision");
println(circle_x - cube_x);
println(circle_y - cube_y);

//circle_x = circle_x;
//circle_y = circle_y;
//cube_x = cube_x;
//cube_y = cube_y;

tempx = move_x;
tempy = move_y;

move_x = moveCubeX;
move_y = moveCubeY;

moveCubeX = tempx;
moveCubeY = tempy;

//stop() ;

}
}
``````
• oops, it seems the copy/paste of the program lines does not work the way I imagine... The lines are there but not displayed as in the program. Is there another mean than ctrlC --> ctrlV to paste program lines to this page ?

• Yup, we highlight the code block and hit CTRL+K. Then it's automatically indented 4 spaces and it's recognized as a code block!
Also, make sure to have 1 line break before and after the block, in case there's normal text before or after!

• regarding the layout of the program lines:

please

• copy paste the lines
• make sure two (or one) empty lines are before the code
• mark / select the code (I assume without these two lines)
• press 'C' in the small tool bar

Chrisir

• Regarding bouncing:

I don't know about bouncing balls but bouncing one ball at walls:

I often (even in the examples) see lines like

`velocity.x = velocity.x *-1;`

but when the velocity is small and in the next iteration of draw() the ball is still in the area where the condition applies (bouncing area / collision area)

`velocity.x = velocity.x *-1;`

is called again. When we add the value to the position, the ball stutters and stays in the bouncing area forever (since value e.g. toggles between +0.5 and -0.5).

To avoid this, at least for normal walls check for left and right [upper and lower] screenborder separately and say

`velocity.x = abs (velocity.x );`

(abs = always positive result) for the left screenborder / wall and

`velocity.x = abs (velocity.x ) * -1;`

(always negative result) for the right wall. The results are always positive or always negative and can not toggle between the two as with

`velocity.x = velocity.x *-1;`

Good to know!

Chrisir

• here is Philips Code

``````// position initiale du cercle et du cube
float circle_x = 300;
float circle_y = 20;
float cube_x = 50;
float cube_y = 150; // déplacement à chaque frame
float move_x = 5.0;
float move_y = -7.1;
float moveCubeX = 1.2;
float moveCubeY = 1.7;
float tempx;
float tempy;
float RadCircle = 50;

void setup() {
size(400, 600);
}
void draw() {
background(#21EA73);
fill(255, 0, 0);
ellipse(circle_x, circle_y, RadCircle*2, RadCircle*2);
fill(0, 0, 255);
ellipse(cube_x, cube_y, RadCircle*2, RadCircle*2);
line(circle_x, circle_y, cube_x, cube_y);

circle_x = circle_x + move_x;
circle_y = circle_y + move_y;
cube_x = cube_x + moveCubeX;
cube_y = cube_y + moveCubeY;

// controle cube
if (cube_x + RadCircle > width) {
cube_x = width - RadCircle;
moveCubeX = -moveCubeX; // cube too close right;
}
if (cube_y + RadCircle > height) {
cube_y = height - RadCircle;
moveCubeY = -moveCubeY; //Cube too close bottom;
}
if (cube_x -RadCircle < 0) {
cube_x = RadCircle;
moveCubeX = -moveCubeX; //Cube too close left;
}
if (cube_y -RadCircle < 0) {
cube_y = RadCircle;
moveCubeY = -moveCubeY; //Cube too close top;
}

// control circle
if (circle_x + RadCircle > width) {
circle_x = width - RadCircle;
move_x = -move_x; //too far right
}
if (circle_y + RadCircle > height) {
circle_y = height - RadCircle;
move_y = -move_y; //too far bottom
}
if (circle_x - RadCircle < 0) {
circle_x = RadCircle;
move_x = -move_x; //too far left
}
if (circle_y - RadCircle < 0) {
circle_y = RadCircle;
move_y = -move_y; //too far top
}

// controle collision

if (sqrt((circle_x - cube_x )*(circle_x - cube_x ) + (circle_y - cube_y)*(circle_y - cube_y))<= RadCircle*2) {
println("Collision");
println(circle_x - cube_x);
println(circle_y - cube_y);

//circle_x = circle_x;
//circle_y = circle_y;
//cube_x = cube_x;
//cube_y = cube_y;

tempx = move_x;
tempy = move_y;

move_x = moveCubeX;
move_y = moveCubeY;

moveCubeX = tempx;
moveCubeY = tempy;

//stop() ;
}
}
``````
• @ Philip

you asked how to do 100 balls

see

• More advanced questions
• From several variables to arrays
• From several arrays to classes
• Why use ArrayList instead of array with append()?

on

http://wiki.processing.org/w/Technical_FAQ

• I had a look to the "more advanced question" and I have to digest all that stuff now before to go further. Apart creating a lot of objects a simple way, do you think this will also give the possibility to declare a common behavior such having all balls rebound each one to each other ? as this was my first idea...

• yes, this is possible, there are a lot of examples or when you search the old forum.

The basic idea for multiple balls is to cluster the vars and functions for one ball in a class

this class is then the blue print for all your balls.

these balls you have in an array (of type class Ball)

so when you move the balls, you just loop over the array and tell each balls to move

here is a approach with an arraylist (no collision yet)

``````//
import java.util.Collections;
import java.util.Arrays;

//
ArrayList<Ball> balls;
int time;
float speed = 1000.0;

//
// ---------------------------------------------------------------
//
void setup()
{
// init
size(800, 600);
// frameRate(3);
// Create an empty ArrayList
balls = new  ArrayList();

// balls.clear();
int j=0;
//we define a rect and put it into an array of PVector
// ------
int magicNumber=90;
int magicNumber2=90*4;

int magicX=220;
int magicY=120;
PVector [] rectsPoints = new PVector [ 362 ];

for (int i = 1; i<magicNumber+1; i++) {  // x const, y moves
rectsPoints[j] = new PVector(magicX, i*4+magicY);
j++;
}
for (int i = 0 ; i<magicNumber; i++) {  // x const, y moves
rectsPoints[j] = new PVector(magicX+magicNumber2, (i+0)*4+magicY);
j++;
}
for (int i = 0 ; i<magicNumber+1; i++) {
rectsPoints[j] = new PVector((i+0)*4+magicX, magicY+magicNumber2);
j++;
}
// ------
for (int i = 0 ; i<magicNumber+1; i++) {
rectsPoints[j] = new PVector(i*4+magicX, magicY);
j++;
}

println (rectsPoints);
// randomize rectsPoints
// Collections.shuffle(Arrays.asList(rectsPoints));
println (rectsPoints);

// ------
// we define a circle
for (int i = 0 ; i<362; i++) {
float r = 200;
float x = r * cos ( radians(i-0) ) + width / 2 ;
float y = r * sin ( radians(i-0) ) + height / 2 ;
// and put both together into our ArrayList balls
balls.add (new Ball(  x, y,
rectsPoints[i].x, rectsPoints[i].y,
3,
color (255, 2, 2) ) );
}
rectsPoints=null;
} // func
//
void draw()
{
background(255);
Ball ball;
for (int i=0; i < balls.size(); i++) {
ball = balls.get(i);
ball.display();
}
if (time<speed)
time++;
} // func
//

// ========================

void keyPressed() {
time = 0;
}

// ====================
// Simple ball class

class Ball {
float startx;
float starty;
float targetx;
float targety;
color myColor;
// float speed;
//float gravity;
float w;
//float life = 255;

Ball(float tempstartX, float tempstartY,
float tempX2, float tempY2,
float tempW, color tempmyColor1 ) {
startx = tempstartX;
starty = tempstartY;
w = tempW;

targetx=tempX2;
targety=tempY2;

myColor=tempmyColor1;
}

void display() {
fill(myColor);
//noStroke();
float x1 = lerp(startx, targetx, time/speed);
float y1 = lerp(starty, targety, time/speed);
ellipse(x1, y1, w, w);
}
} // class

// ====================
``````
• Thank you Chrisir for your help ! it is of course not as to deal with the squaring of the circle, but I think I still have a lot to learn before playing billiards with all that balls... i'll be back later with some progress...

• This is something approaching to what I hope to have: creating n balls and have collisions between all (and the window bounds). nevertheless, I still have the issue that some rebound against the others and some do not ! Do you have an idea why ? And to help solving the problem, do you know if and how is it possible to have the number of each ball printed in it ?

here is the new code :

``````// new balls with collision

// Number of Balls to create
final int NumeroBalle = 5;
// Positions
float[] posX = new float[NumeroBalle];
float[] posY = new float[NumeroBalle];
// Movements (linear)
float[] speedX = new float[NumeroBalle];
float[] speedY = new float[NumeroBalle];
float[] radius = new float[NumeroBalle]; // Radius of the balls
// Colors
color[] ballColor = new color[NumeroBalle];
int[] red = new int[NumeroBalle];
int[] green = new int[NumeroBalle];
int[] blue = new int[NumeroBalle];

void setup()
{
size(600, 400);
smooth();

// Initialize balls data
for (int i = 0; i < NumeroBalle; i++)
{
red[i] = int(random(255));
green[i] = int(random(255));
blue[i] = int(random(255));
ballColor[i] = color(red[i], green[i], blue[i]);
radius[i] = random(20, 30); //random radius between
//starting position of each ball
posX[i] = random(radius[i], width - radius[i]);
posY[i] = random(radius[i], height - radius[i]);
//*******
//this is another mean to initialise ball positio to prevent intial distance
//less than radius1 + radius2, because of collision computation
//posX[i] = 2*i * radius[i] + radius[i] ;
//posY[i] = 2*i * radius[i] + radius[i];
//********
speedX[i] = random(-2, 1);
speedY[i] = random(-1, 2);

}
}
void draw()
{
// Erase the sketch area
background(#AAFFEE);
for (int i = 0; i < NumeroBalle; i++)
{
// Compute the new ball position
moveBall(i);
// And display it
displayBall(i);
displayLine();
//collisions
Collisions();
}
}

void moveBall(int n)
{
// Move by the amount determined by the speed
posX[n] += speedX[n];

// Check the horizontal position against the bounds of the sketch
if (posX[n] < radius[n] || posX[n] > width - radius[n])
{
// We went out of the area, we invert the h. speed (moving in the opposite direction)
// and put back the ball inside the area
speedX[n] = -speedX[n];
posX[n] += speedX[n];
}
// Idem for the vertical speed/position
posY[n] += speedY[n];
if (posY[n] < radius[n] || posY[n] > height - radius[n])
{
speedY[n] = -speedY[n];
posY[n] += speedY[n];
}
}

//******************
// controle collision
void Collisions() {

for (int n = 0; n < NumeroBalle; n++) {
for (int m = 1; m < NumeroBalle; m++) {
if (sqrt((posX[n] - posX[m] )*(posX[n] - posX[m] ) + (posY[n] - posY[m])*(posY[n] - posY[m]))<= (radius[n] + radius[m])) {

float tempx = speedX[n];
float tempy = speedY[n];

speedX[n] = speedX[m];
speedY[n] = speedY[m];

speedX[m] = tempx;
speedY[m] = tempy;

}
}
}
}
//******************

void displayBall(int n)
{
// define ball
//noStroke();
fill(ballColor[n]);
ellipse(posX[n], posY[n], radius[n] * 2, radius[n] * 2);
}

void displayLine()
{
//draw line between each ball
for (int n = 0; n < NumeroBalle; n++) {
for (int m = 1; m < NumeroBalle; m++) {
line(posX[n], posY[n], posX[m], posY[m] );

}
}
}

// end
``````
• That is a cool bump simulation. I've got 1 online too! Check it out:

http://studio.processingtogether.com/sp/pad/export/ro.91xkuWl51J\$Vp/latest

• Thanks GTL ! With the code I proposed you can also change the number of balls at line 4 -> final int NumeroBalle = 5; and increase it up 100 even more, in that case you have to inactivate the displayLine() at line 55, and reduce the radius at line 30 to random(2,3)... amazing too... The one you've posted is cool too ! Do you have the code for this one ? ... and any idea with my question why some bumps some not ?

• Ooops ! I found your code, as far as it was directly under the "game" and didn't scroll down the page before to answer, but play the game...

Sign In or Register to comment.