# Bizarre results in pool sim

This topic is 2090 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I've been following some of the maths posted here: http://www.gamasutra.com/view/feature/3015/pool_hall_lessons_fast_accurate_.php and trying to integrate collisions and response into my pool game, but I'm getting VERY strange results!

The collision code and update code below!

 void UpdateBalls(Ball* balls) { float frictionCoefficient = 0.15f; for(int ball = 0; ball < TOTALBALLS; ball++) { if(balls[ball].currentVelocity.Length() > 0.0f) { balls[ball].position += balls[ball].currentVelocity; //put something in here for friction balls[ball].currentVelocity -= balls[ball].currentVelocity.Normalise() * frictionCoefficient; //check if the magnitude of the velocity vector is less than 1.0f, if so make it stop. if(balls[ball].currentVelocity.Length() < 1.0f) { balls[ball].currentVelocity = Vector3(0.0f,0.0f,0.0f); } } } } 

 void CheckForBallCollisions(Ball* balls) { for(int currentBall = 0; currentBall < TOTALBALLS-1; currentBall++) { for(int eachBall = currentBall + 1; eachBall < TOTALBALLS; eachBall++) { //check if there is possibility for collision, if not, continue //get distance float distance = (balls[currentBall].position - balls[eachBall].position).Length(); if(balls[currentBall].currentVelocity.Length() < distance - 2.0 * BALL_RADIUS) continue; //get vector between balls Vector3 betweenVec = balls[eachBall].position - balls[currentBall].position; //now test the dot product between the vector and movement if(betweenVec.DotProduct(balls[currentBall].currentVelocity) <= 0) continue; //now use the dot product again to find the point on the velocity vector closest to the //center of the eachBall by projecting the vector between the two balls onto the current balls' //velocity vector distance = betweenVec.DotProduct(balls[currentBall].currentVelocity.Normalise()); //using pythagoras get f, the distance from the center of the other ball being tested and the //velocity vector of the currentball float f = (betweenVec.Length() * betweenVec.Length()) - (distance * distance); //if f is bigger than 2 * the ball radius squared they can't collide so go to the next ball if( f > (BALL_DIAMETER * BALL_DIAMETER)) continue; //find t, the value of the ball radius * 2 squared minus f float t = BALL_DIAMETER * BALL_DIAMETER - f; //if the distance to the other ball is more than the currentball's velocity then there is no way they will hit float distanceToBall = distance - sqrt(t); if(distanceToBall > balls[currentBall].currentVelocity.Length()) continue; //balls[currentBall].position += balls[currentBall].currentVelocity.Normalise() * distance; //now give them their new velocities //find the normalized vector from ball 1 to ball2 Vector3 normal = balls[currentBall].position - balls[eachBall].position; normal = normal.Normalise(); //find the components of the movement vectors along n float a1; float a2; if(balls[eachBall].currentVelocity.Length() > 0.0f) a2 = normal.DotProduct(balls[eachBall].currentVelocity.Normalise()); else a2 = 0.0f; if(balls[currentBall].currentVelocity.Length() > 0.0f) a1 = normal.DotProduct(balls[currentBall].currentVelocity.Normalise()); else a1 = 0.0f; //find p, the impulse factor. The masses of the two balls are the same so m is omitted //from this equation float p = a1-a2; //calculate new velocities balls[currentBall].currentVelocity = balls[currentBall].currentVelocity + p * normal; balls[eachBall].currentVelocity = balls[currentBall].currentVelocity - p * normal; } } } 

When I'm updating I call the collision code before the update position code

any ideas?

Thanks and hugs in advance

##### Share on other sites
How is time handled in your simulation? I don't see a time-scaling factor anywhere, so variances in frame execution time will lead to destabilization of your physics. In particular the thing that strikes me as suspicious is your check to see if the velocity vector is too short to reach the destination ball; since you don't have a time scale in there, you don't know how far the ball is actually going to travel, so you might miss collisions if the time step is sufficiently short.

##### Share on other sites
Hi ApochPiQ, thanks for replying. I'm using an engine from "Advanced 2D Game Programming" by Jonathan Harbour, in the engine instead of using a delta time value there is a 'stopwatch' class. Basically, a frame is executed every 14 ms or so, so each frame has balls travelling a fixed distance minus friction every frame. In my simple example, I am using the current velocity for this particular frame to test if the ball reaches the other ball, I hope that makes sense.

As an aside, I'm looking to rewrite my own engine very soon that works on a delta time value. The book presents a great way to build a library of things like vectors, particle emitters and so on but I don't use the engine's update functions as it is all obfuscated with various oop-style casts and inheritance etc etc.

##### Share on other sites
Gotcha, that makes sense.

Have you checked to be sure that a pair of balls cannot collide more than once in a given frame? e.g. ball A hits ball B, then later in the loop, B hits A, and counteracts the collision incorrectly?

 Nevermind, on closer reading of your code I think I see the problem. Specifically, consider this situation:

- Ball A is moving at 0 velocity in this frame
- Ball B is moving towards A at 10 units/sec
- You check ball A to see if it can hit Ball B
- Since A isn't moving, you early out and continue to ball B
- Ball B has nothing to check against since it is the last ball
- No collision
- B passes through A Edited by ApochPiQ

##### Share on other sites
I've now tried changing it to this...

 for(int currentBall = 0; currentBall < TOTALBALLS-1; currentBall++) { for(int eachBall = 0; eachBall < TOTALBALLS; eachBall++) { if (eachBall == currentBall) continue; . . . 

Now it acts really weird!

##### Share on other sites
To be more specific....the balls tend to 'cluster together' even more...

##### Share on other sites
Reading through your code it seems to me that your collision-response (or the lack of it) might cancel out further collision-detection, which might result in the clustering of the balls. Another point is be that you only consider the first level of collisions, so if a ball moves into another ball as a result of the collision this will not be treated right. The physical part of the response seems ok to me.

I would recommend that you split up the collision-detection and collision-response for easier debugging. Later on you can merge the code again if it is a performance issue.
First find all collisions and save them in a set (or list); then iterate over the list and calculate the responses.
Maybe it also helps if you minimize the amount of balls in play, it's much easier to determine how many collisions you have between 4 balls than between 17 balls.

##### Share on other sites
There is a typical situation in collision detection and handling (I haven't read through your code) when objects collide, you mirror their velocities as you should, then in the next update the balls are still collision (because they haven't moved totally out of collision since you have a dumping feature to slow balls down), so their velocity will be mirrored again. And again in the next update. There you have your sticking balls. It's sometimes observed as "shaking" balls depending on the refresh rate of your simulation.

To overcome this you either have to make sure the objects get out of collision by explicitly moving them apart in the collision response. This can mean problems with multiple colliding objects.

Or you can use physics simulation instead, with forces (depending on the collision depth, like spring forces), acceleration, etc. Edited by szecs

##### Share on other sites
Ok thanks all, I've made a few changes to my code. First of all I've changed my update loop not to use a stopwatch but use a delta time value instead. I've also seperated the collision detection and response. It now goes like this: when updating the position of my balls I first check if this frame causes a collision, if so step back and seperate the balls, THEN give them their new velocities. The clustering isn't as bad now at all, no more overlapping of balls, but instead the balls stick end to end!

 void UpdateBalls(Ball* balls,float dt) { float frictionCoefficient = 0.05f; float distance = 0.0f; Ball* ballPtr = NULL; for(int ball = 0; ball < TOTALBALLS; ball++) { if(balls[ball].currentVelocity.Length() > 0.0f) { //put something in here for friction balls[ball].currentVelocity -= balls[ball].currentVelocity.Normalise() * frictionCoefficient; //check if the magnitude of the velocity vector is less than 1.0f, if so make it stop. if(balls[ball].currentVelocity.Length() < 1.0f) { balls[ball].currentVelocity = Vector3(0.0f,0.0f,0.0f); } //check if ball can move forward without hitting another ball if(!CheckCollisions(balls,ball,&distance,&ballPtr,dt)) { balls[ball].position += balls[ball].currentVelocity * dt; } else { //balls[ball].currentVelocity[X] = 0.0f; //balls[ball].currentVelocity[Y] = 0.0f; CollisionResponse(&balls[ball],ballPtr,dt); } } } } 

 void CollisionResponse(Ball* ball1,Ball* ball2,float dt) { //find the normalized vector from ball 1 to ball2 Vector3 normal = ball1->position - ball2->position; normal = normal.Normalise(); //find the components of the movement vectors along n float a1; float a2; if(ball2->currentVelocity.Length() * dt > 0.0f) a2 = normal.DotProduct(ball2->currentVelocity.Normalise()); else a2 = 0.0f; if(ball1->currentVelocity.Length() * dt > 0.0f) a1 = normal.DotProduct(ball1->currentVelocity.Normalise()); else a1 = 0.0f; //find p, the impulse factor. The masses of the two balls are the same so m is omitted //from this equation float p = a1-a2; //calculate new velocities ball1->currentVelocity = ball1->currentVelocity + p * normal; ball2->currentVelocity = ball1->currentVelocity - p * normal; //seperate the balls ball1->position += ball1->currentVelocity.Normalise(); ball2->position += ball2->currentVelocity.Normalise(); } 

Video soon

##### Share on other sites

//calculate new velocities
ball1->currentVelocity = ball1->currentVelocity + p * normal;
ball2->currentVelocity = ball1->currentVelocity - p * normal;

//seperate the balls

ball1->position += ball1->currentVelocity.Normalise();
ball2->position += ball2->currentVelocity.Normalise();

I think you have a mistake in the second line where you calculate the current velocity of the balls. You're using the currentVelocity() of of ball1 instead of ball2. I also think that you should not normalize the current velocity at the end, because not just the direction but also the magnitude of the velocity matters in this context.

##### Share on other sites

[quote name='Lil_Lloyd' timestamp='1338420610' post='4944817']
//calculate new velocities
ball1->currentVelocity = ball1->currentVelocity + p * normal;
ball2->currentVelocity = ball1->currentVelocity - p * normal;

//seperate the balls

ball1->position += ball1->currentVelocity.Normalise();
ball2->position += ball2->currentVelocity.Normalise();

I think you have a mistake in the second line where you calculate the current velocity of the balls. You're using the currentVelocity() of of ball1 instead of ball2. I also think that you should not normalize the current velocity at the end, because not just the direction but also the magnitude of the velocity matters in this context.
[/quote]

If I change that the cue ball comes to a COMPLETE standstill when colliding with the other ball!

##### Share on other sites
Now, I've got some 'ok' results, not perfect but much better than what they were! My new code is as follows...

 void CollisionResponse(Ball* ball1,Ball* ball2,float dt) { //now give them their new velocities //find the normalized vector from ball 1 to ball2 Vector3 normal = ball1->position - ball2->position; Vector3 unitNormal = normal.Normalise(); //make it so the balls only touch! //penetration depth float depth = BALL_DIAMETER - normal.Length(); //push them apart ball1->position += unitNormal * depth * 0.5f; ball2->position -= unitNormal * depth * 0.5f; Vector3 resultVec = ball1->currentVelocity - ball2->currentVelocity; //impact velocity along normal float velNorm = resultVec.DotProduct(unitNormal); Vector3 velNorm2 = velNorm* unitNormal; //tangent velocity Vector3 Vt = resultVec - velNorm2; if(velNorm > 0.0f) velNorm2 = Vector3(0.0f,0.0f,0.0f); resultVec -= Vt + velNorm2 * 2.0f; ball1->currentVelocity += resultVec * 0.5f; ball2->currentVelocity -= resultVec * 0.5f; } 

I'd post a video but for some reason, FRAPS causes the game update and physics to go extremely weird....

Thanks to all that gave suggestions, I'll post a vid as soon as I solve the FRAPS thing...

##### Share on other sites
Maybe when FRAPS starts recording your frame rate drops? If you are using an Euler-Integrater your delta time could be too big which causes your derivatives to be off and therefore updates are more chaotic.