Sign in to follow this  
iudelta

Ball bouncing and rolling down slopes

Recommended Posts

I'm creating a 2D game and nearly have the physics code completed. But I've run into an odd problem. I don't know how to detect when the ball should no longer be moving. I would have thought it would have been as simple as checking whether ball.velocity == 0, but due to inaccuracies (and poor design on my part), the ball in my game never truly stops moving. For example, imagine a ball is dropped from a height of 200 pixels. Each step (I'm using fixed time steps for the physics), I add 0.1 to the velocity in the y-direction. Everytime the ball hits the ground, it bounces back up, but to a shorter and shorter height. It eventually reaches a point where it gets "stuck" bouncing back and forth at extremely small values. Basically my code looks like this:
ball.velocity.addY(0.1); // Gravity accelerating the ball every time step.
ball.updatePosition();

if(ball collides with ground)
    // Calculate new velocity of the ball after it bounces.
See where the problem is? The ball is always going to have a velocity of at least 0.1 when colliding with the ground because I'm adding that for gravity. It'll never reach zero. So I decided the fix for this problem would be:
ball.velocity.addY(0.1); // Gravity accelerating the ball every time step.
ball.updatePosition();

if(ball collides with ground)
    // Calculate new velocity of the ball after it bounces.
    if(newYVelocity >= -0.1)
        ball.yVelocity = 0
This sort of works. If the ball can't "escape" the ground (overcome gravity), then I can go ahead and set the ball's y-velocity to 0. It seems hacky, but at least the ball comes to a stop now. This only works when the ground is flat though. If it has any slope to it, this no longer works. So I got rid of it. Here's another example. Imagine a ball dropped onto two walls merging together like this: Photobucket - Video and Image Hosting My code does what I expect it to do, up until it has slowed down to a near stop from friction and bouncing. But again, since gravity is added at each time step, the ball's velocity never reaches zero. It just keeps bouncing between the two walls at tiny values. To the user, it's not noticeable that the ball is still moving. But I need to know when the ball has stopped because I need to detect when the player's turn is over. I thought the solution to this could be to add gravity only when the ball is in the air, but that won't work because then the ball won't roll down the slopes anymore. I'm all out of ideas. I'm probably just going about this the wrong way, but I don't know what the "correct" way is. Can anybody point me in the right direction? Thanks.

Share this post


Link to post
Share on other sites
it's late and I'm about to go to bed, but what you want is to project the vector of your velocity into the walls normal

there's the friction and bounce example
http://www.harveycartel.org/metanet/tutorials/tutorialA.html#section0

you want to bounce in the opposite direction over the normal of the wall. (the normal is explained in the article).

This explains projection and has a flash example. Your going to have to use vector math. (I'm relatively new to it, so I can't explain much).
http://www.harveycartel.org/metanet/tutorials/tutorialA.html#appendixA

proj.x = ( dp / (b.x*b.x + b.y*b.y) ) * b.x;
proj.y = ( dp / (b.x*b.x + b.y*b.y) ) * b.y;

Also for circle to line remember to use a ray or some such of hitdetection to find exactly where it hits.

//edit oh just noticed your problem, I read it wrong. Still maybe someone will find the above stuff useful.

Share this post


Link to post
Share on other sites
Quite a lot of physics engines handle this problem by simply freezing the physics update for the ball when the ball's state doesn't change significantly over the course of a period of time.

The physics is re-enabled when a new physics event occurs to the ball (eg. a new contact/collision).

So, a bit of pseudocode...


#define EPSILON (1/(float)1<<6)

// you want this to be big enough to prevent the situation where the ball is
// thrown 'up' and for several frames is slow enough to be considered dead
// still at it's apex.
#define NUM_FRAMES_UNTIL_FREEZE 6


void CPhysObj::UpdateDynamics(float fTimeStep)
{
if (mbFrozen)
{
return;
}

// do dynamics here (integration etc.._
// ...


// now check for freeze
if ((abs(mLinearMomentum) <= EPSILON) && (abs(mRotationalMomentum) <= EPSILON))
{
miFramesUntilFreeze--;
}
else
{
miFramesUntilFreeze = NUM_FRAMES_UNTIL_FREEZE
}

if (miFramesUntilFreeze <= 0)
{
mbFrozen = true;
}
}

// signalled when a collision occured with the ball
void CPhysObj::CollisionEvent()
{
// unfreeze the physics object so dynamics will occur the next frame and
// beyond.
mbFrozen = false;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by FReY
Quite a lot of physics engines handle this problem by simply freezing the physics update for the ball when the ball's state doesn't change significantly over the course of a period of time.

The physics is re-enabled when a new physics event occurs to the ball (eg. a new contact/collision).

I had actually thought of an idea similar to that, but then I thought to myself, "I must be doing something wrong... there has to be a better way." But it looks like I'll use the freezing technique. Thanks for the help.

Share this post


Link to post
Share on other sites
Well consider two things:

1. Does the small, unnoticable motions really affect gameplay? It may seem bothersome that your objects never really 'stop', but that's the way that nature really works.

2. It's a fairly common tactic to define some epsilon that is an upper bound for what is equal to 0. Don't consider it cheating to change an object's velocity to 0 when it goes beyond this point.

I use a combination of the two, although it rarely comes up that it's really necessary. Let the objects vibrate unnoticeably, but never evaluate for 0, alway use an epsilon in every comparison.

Share this post


Link to post
Share on other sites
Quote:
Original post by erissian
Well consider two things:

1. Does the small, unnoticable motions really affect gameplay? It may seem bothersome that your objects never really 'stop', but that's the way that nature really works.

2. It's a fairly common tactic to define some epsilon that is an upper bound for what is equal to 0. Don't consider it cheating to change an object's velocity to 0 when it goes beyond this point.

I use a combination of the two, although it rarely comes up that it's really necessary. Let the objects vibrate unnoticeably, but never evaluate for 0, alway use an epsilon in every comparison.

I'm making a turn-based game. Each turn ends when the ball comes to a stop. That's why I need to know when the ball "stops". Other than that, I don't care about unnoticeable motions. So using an epsilon should solve this problem.

I'll need to check it for multiple frames though, like FReY suggested. Just because the ball's velocity is close to zero doesn't mean the ball has stopped... like in the second example, where the ball rolls up the hill for some time, comes to a stop, then rolls back the other way.

Share this post


Link to post
Share on other sites
Quote:
Original post by iudelta
I'll need to check it for multiple frames though, like FReY suggested. Just because the ball's velocity is close to zero doesn't mean the ball has stopped... like in the second example, where the ball rolls up the hill for some time, comes to a stop, then rolls back the other way.


In that case, you could also account for forces. If your velocity is near zero, and the horizontal force is near zero, and the ball is in a collision state with the ground beneath it, then it's done moving.

Also, you could profile your playing field to find the dips where the ball would rest. You could calculate the potential energy required to move a minimum distance outside of the pit, and compare it to the ball's potential energy at the moment it enters the pit. If it's too small, then you can assume the ball would be trapped there. In the case of flat ground, near zero velocity would be good enough.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this