Circle to circle collisions and physics

Hi Nerds,

I am currently thinking about an experiment ?ncluding circle/circle collisions and I would like to write it all from scratch just for learning reasons. But since it should still run at a solid frame rate with many circles I was wondering if box2D would be alot faster than for example a simple collision/velocity code based on something like this:

http://freespace.virgin.net/hugo.elias/-…–snokr.htm

I know this questions is kind of vague but anyways I would be really glad about some helpful links and ideas. I have never touched box2D so any experience reports about that are wlcome too!

Thanks!

I actually did this for one of my classes: circle collision by hand - its the last example in this zip:

http://lab.impssble.com/files/iLab003/–…-istrib.zip

Also zips 004 and 005 have chipmunk examples setup
http://lab.impssble.com/files/iLab003/

The chipmunk stuff is a little buggy but it might be useful.

Theo

hey theo, thank you very much! Do you know if box2D has any major performance improvements compared to yours?

most definitely!!
it is a very optimized library.

The last example of the 005 folder is a chipmunk example that has balls falling and calling collision callbacks to make sounds on impact. might also be worth looking at.

Theo

nice !

just wanted to point out there are are some simple and optimized ball / ball collision code in these course materials:

http://www.makingthingsmove.org/blog/?cat=5

including these super fast 2d ball collision routines (using binning):

http://www.makingthingsmove.org/blog/wp-…-0-code.zip

and an example

of approximating the contour as a series of balls for collision against complex bodies.

  • zach

thank you very much, I will look into that too!

EDIT: BTW what is binning? Simple explanation would be great! Thanks!

EDIT2: I just looked the word up in the dictionary, sorry :slight_smile:

Hi, the source codes you posted helped me alot so far but I am having some trouble when I try to implement a good way to take the mass of each circle into account. What my program does right now is simply to add gravity to each circle and let them damp/bounce of the window edges. so what I expect to happen is that they move down and stop moving after some time (because of th damping) and position themselves at the bottom of the window, not overlapping. but instead they stay hectic and don’t stop moving. I think it has something to do with the collision code, right now it’s like this:

  
//------------------------------------------------------------  
void particle::checkCollision(particle & p){  
    float radius = rad+p.rad;  
	float impactSpeed;  
	ofxVec2f impulse, impact;  
	  
	ofxVec2f normal = pos-p.pos;  
	float dist = normal.length();  
	  
	if(dist < radius){  
		float totalVelMag = vel.length() + p.vel.length();  
		float frictionalLoss = 0.5;  
		totalVelMag *= frictionalLoss;  
		  
		frc += (totalVelMag * 0.5)  *  normal.normalized();  
		p.frc += (totalVelMag * 0.5)  * -normal.normalized();  
	}  
	  
}  

how would I take the mass of each particle into account the right way(based on the radius of each circle)? Furthermore what could cause the particles to not stop moving and get all hectic (this escpecially happens when they have different radii, not so obvious when they have the same radius)?

Thanks!

Well I would imagine they should lose quite a lot force as you have frictionalLoss set to 0.5
So every collision they should be losing 50% of their energy.

In terms of the mass coming into to effect it is quite simple.

The mass of a circle can be based on the area of the circle. So from the radius, use PI * radius * radius to get the area.

When you have the area of the two circles find out how their area relates to the total of area of the two circles combined.

ie:

  
float areaMe = radius & radius; //(no need for PI as it is a constant)  
float areaHim = P.radius * P.radius;  //(no need for PI as it is a constant)  
  
float total = areaMe + areaHim;  
  
float myRatio = areaMe / total;  
float hisRatio = areaHim / total;  
  
frc += hisRatio * ( (totalVelMag * 0.5)  *  normal.normalized() );        
p.frc += myRatio * (  (totalVelMag * 0.5)  * -normal.normalized() );  

Hope that helps!
Theo

THanks theo, I will check that!

Yeah, I don’t understand why they don’t stop moving. It only happens though when they get attracted to a certain spot or hit the bottom of the window (due to gravity). I think the problem is that they get maybe new velocity everyframe and get pushed away from the bottom of the window again and again?

Dunno, it’s weird :slight_smile:

hey moka,

so it turns out that there was a problem with the way I was moving the circles apart.
I was using their velocity as a way to figure out which direction to move them in - but I should of just been using the vector between their centers.

So here is the same code but with gravity and relative mass

  
//--------------------------------------------------------------  
void testApp::setup(){	  
	ofBackground(255,255,244);  
	ofSetVerticalSync(true);  
	  
	int numBalls = 30;  
	  
	for(int i = 0; i < numBalls; i++){  
		basicParticle tmpBall;  
		tmpBall.setPosition( ofRandom(10, ofGetWidth() ), ofRandom(10, ofGetHeight() ) );  
		tmpBall.setVelocity( ofRandom(-3, 3), ofRandom(-3, 3) );  
		tmpBall.radius = ofRandom(10, 38);  
		tmpBall.setFriction(0.98);  
		  
		//add the new ball into our array (vector)   
		balls.push_back(tmpBall);  
	}	  
  
}  
  
//--------------------------------------------------------------  
void testApp::update(){  
  
	for(int i = 0; i < balls.size(); i++){  
		balls[i].vel.y += 0.05;  
	}  
	  
	for(int i = 0; i < balls.size(); i++){  
  
		//okay - lets collide!  
		//for each particle we need to calculate its interaction with every other particle   
		//so we need another for loop  
		  
		//lets make some vars - we avoid making them in the for loop for speed sake.   
		ofxVec2f pDist;  
		float pLen = 0;  
		float radiusLength =0;  
		float amntOverlapped = 0;  
		  
		//this loop checks the collosion of the current particle against all other particles before it  
		//we don't check against the collision of all particles as then we will be check the collisions twice  
		//ie: 0 vs 5 and 5 vs 0 -- this loop makes sure we only check collisions once		  
		for(int k = 0; k < i; k ++){  
			  
			pDist = balls[i].pos - balls[k].pos;  
			  
			//to see if they have collided we just need to check if the straight line dist is less than both radii combined  
			radiusLength = balls[i].radius + balls[k].radius;  
  
			//the straight line dist between them  
			pLen = pDist.length();  
			  
			//if this is true then calculate the collision  
			if( pLen <  radiusLength ){  
				  
				//-------- part 1 - calc the velocity  
				//for this we take the vector between them ( pDist ) and we normalize it so we can just use it for direction  
				//we then add together the balls original speed (not velocity) and calculate a new velocity based on:  
				//the direction of the ball after collision multiplied by 50% of their combined speed.   
				  
				//calculate the total speed of the two balls  
				float totalVelMag = balls[i].vel.length() + balls[k].vel.length();  
				  
				//then add to their velocity 50% of the speed * the vector they need to move in  
				//you could look at radius if you want and change the amnt of the vel of each based on mass (radius squared)  
				  
				float frictionalLoss = 0.95;  
				totalVelMag *= frictionalLoss;  
				  
				float massMe = balls[i].radius * balls[i].radius;  
				float massHe = balls[k].radius * balls[k].radius;  
				  
				float total = massMe + massHe;  
				  
				float amntHe = massHe / total;  
				float amntMe = massMe / total;  
				  
				ofxVec2f oldVel = balls[i].vel;  
  
				balls[i].vel += amntHe * ( (totalVelMag * 0.5 )  *  pDist.normalized() );  
				balls[k].vel += amntMe * ( (totalVelMag * 0.5  )  * -pDist.normalized() );  
				  
				//------ part 2 - overlapping balls   
				//we also need to figure out how much they are overlapped and move them apart so they are only just touching  
				amntOverlapped =  (radiusLength - pLen);  
				  
				//we then need to move the particles in opposite directions by 50% of the amntOverlapped  
				//so when we finish they are touching each other  
				//to do this we normalize the distance between them  
				  
				ofxVec2f delta;  
				delta = balls[i].pos - balls[k].pos;  
				  
				ofxVec2f revIVel = delta.normalized();  
				ofxVec2f revKVel = ( -1 * delta ).normalized();  
	  
				//now move them - after this they should both not be overlapping  
				balls[i].pos +=  revIVel * amntOverlapped * 0.5;  
				balls[k].pos +=  revKVel * amntOverlapped * 0.5;			  
				  
			}  
			  
		}  
		  
	}  
  
  
	//we calculate all the balls collisions first   
	//then we go through and call update to update their position.  
		  
	for(int i = 0; i < balls.size(); i++){  
  
		//make it bounce of the edge of the screen  
		if( balls[i].pos.x + balls[i].radius > ofGetWidth() ){  
			balls[i].pos.x = ofGetWidth()-balls[i].radius;		//set its position to be at the edge  
			balls[i].vel.x *= -0.96;								//reverse its x velocity  
		}  
		if( balls[i].pos.x - balls[i].radius < 0 ){  
			balls[i].pos.x = balls[i].radius;					//set its position to be at the edge  
			balls[i].vel.x *= -0.96;								//reverse its x velocity  
		}  
		if( balls[i].pos.y + balls[i].radius > ofGetHeight() ){  
			balls[i].pos.y = ofGetHeight()-balls[i].radius;		//set its position to be at the edge  
			balls[i].vel.y *= -0.96;								//reverse its y velocity  
		}  
		if( balls[i].pos.y - balls[i].radius < 0 ){  
			balls[i].pos.y = balls[i].radius;					//set its position to be at the edge  
			balls[i].vel.y *= -0.96;								//reverse its y velocity  
		}  
		  
		balls[i].update();  
	}  
	  
}  

thank you very much theo, I ill tell you ho it works :slight_smile:

unfortunatelly it’s still kind of like the same. If i use alot of circles (200) at really different scales they don’t stop moving and keep shaking at the bottom of the window. I guess it’s some kind of inaccuracy :slight_smile:

Hi Moka,
have you read this article http://www.teknikus.dk/tj/gdc2001.htm? it explains how to use the verlet integrator and also explains how to create constraints and how to solve them, from there its pretty easy to make circle to circle collision.
i created a little physics addon for the Parque project (http://forum.openframeworks.cc/t/parque/2003/0) which i’ll be releasing the next couple days, which is based on that article and has particle to particle collision.
hope it helps.
Rui

Hey Rui,

Thank you very much that article is REALLY great, even though I portet parts of the toxiclibs verlte physics class for a ribbons project a few month back this article finally made me understand what verlet physics really is about, I am looking forward to see your class, even though I will do my own since I want to learn how thinks work on my own, thanks again to all of you for being so helpful!

Cheers

Moka

Yes I see the problem you mentioned Moka - especially when having lots of balls of different sizes.

It is essentially the reason why you need to look at vertlet or euler integrators: trying to move the overlapping balls apart is an almost impossible situation as by un-overlapping two balls you might be moving one of them to overlap another and because you can’t magically un-overlap all the balls at the same exact moment, the more balls you have the more likely you are to create situation where the balls can’t come to rest.

As I am sure you realize the code was meant as a basic introduction to my students of the ideas involved with collision - box2d or chipmunk both have really good systems for dealing with these problems and I think they even have smart caching code which basically stops checking collisions with objects that have come to rest against each other.

Also might be worth checking out is memo’s ofxMSAPhysics which is using verlet for 2d and 3D collisions - probably a much better guide than my quick hack posted above :smiley:

Theo

Hi theo

in your examples :twisted:

i want to run the chipmunk, is very interesting, you have a versionn for windows??, o some idea for run it on windows :smiley:

Hey group,
I’m pretty new to OF and I don’t understand how to load the example code. I’d downloaded and unzip files and I don’t know where to place them. I tried placing them in my “Myapp” folder. When I try to open it in Xcode, it tells me no SDK is loaded.