Rolling ( & other ball-spin related physics)?

Started by
8 comments, last by oliii 15 years, 9 months ago
Hey there, So I've got the collision detection and reaction working for the little player-controlled ball in my game. Basically my game involves a little robotic ball that will eventually roll around levels, solving various puzzles and defeating enemies along the way. Right now the ball can bounce off of flat and curved surfaces, but that's about it. I want to implement rolling, so that if the ball's velocity is below a minimum level, the ball will lock into "roll" mode instead of bounce off of the surface. The ball's rotational velocity will also be an independent variable, and the ball will interact with its environment accordingly (when bouncing, bounce angle will be affected by ball spin, etc.) Also, using the arrow keys to accelerate the rotational velocity in one direction or the other will cause friction against the surface the ball is resting on, therefore causing it to roll faster. Anywaysss... the main thing that I'm having trouble wrapping my head around is how I would handle the beginning of the roll mode lock. According to the angle and the velocity that the ball hit the surface at, I have to calculate a new speed velocity that pushes the ball along the surface vector. Also I have to somehow calculate a rotational velocity based on the friction of the ball and the surface. When I imagine a marble being gently tossed at an angle onto a surface, the marble slides a little bit on the surface, but then quickly, because of friction, it begins rolling. The question is just how to implement this in software. Any help is appreciated! Peace and <3, dgm
Advertisement
you're correct in assuming friction causes rolling. If there was no friction, there would be no rolling at all (because the change in angular momentum at the point of collision on a ball will be zero).

First, angular motion in 2D is relatively similar to linear motion. Your body (the ball), has an inertia, that will dictate how much it is susceptible to changes its angular velocity (like the mass influencing the linear momentum).

When your ball collides with a surface, a collision impulse will be generated, perpendicular to the collision plane, that will instantaneously change its linear moomentum (and angular, if it wasn't a perfect sphere).



http://members.gamedev.net/oliii/polygon.rar, example 7

Also look at Chris Hecker's phyiscs tutorials. My code is based on his stuff.


There will also be a friction component, tangent to the collision plane, that will act in the opposite direction of the tangential velocity.

That will generate angular momentum, until the rolling motion and the linear motion are in equilibrium : the contact velocity becomes zero, and the ball will roll prefectly on the surface.

You can approximate the amount of friction, by taking the collision impulse, and multiply it by a coefficient. The direction of the friction will be opposite the velocity, projected on the collision plane.

I use a different model sometimes, which is very similar to the calculation of the collison impulse, but rotated 90 degrees. Not sure how accurate it is though (friction is a pain).

Everything is better with Metal.

Thanks for the help, oliii!

I think I'm beginning to understand that I really don't have to cheat as much as I initially thought I would - "locking" the ball into roll "mode" now doesn't seem to be necessary (er... I think).

I'm having a bit of a hard time comprehending all of the formulas in Chris Hecker's articles, though. Plus, I tried looking through your example code in C++, but the only language I know right now is Python and I'm having a bit of trouble trying to comprehend what your code does, especially with regards to the pointers.

Right now I've got a ball that just moves with a velocity, and I don't do anything with regards to mass, acceleration, or force, like in Chris Hecker's articles. I'm assuming that I should be implementing these things as well?

Also, I'm working with a moving ball interacting with static objects (such as walls and ramps), so shouldn't the formulas be slightly different in this case?

Peace and love,
dgm
I think the way I would approach it would be to calculate the effect on the rotational velocity upon impact using some sort of moment (or torque) based approach.
For example if you know the component of the object's velocity which is parallel to the plane it's colliding with, and you have some sort of constant that states the magnitude of the friction between the ball and the particular surface, you could use these to determine the force that the friction is going to apply to the part of the ball that's making contact with the surface. *gasps for oxygen after that sentence*
From there it's just a matter of multiplying the force with the radius of the ball to determine the overall effect on the rotational velocity.
It's pretty rough and there would probably be other things to take into consideration, but it makes sense to me.

cheers,
metal
Regarding acceleration, mass etc- it depends how accurate you want your game to be. I like to create games that are based around simple newtonian physics. To me it makes things easier in the long run because once you have a complete system set up, all you need to do is apply a force to an object and the rest is just done automatically. You can aim to create an interface which becomes as high level as something like ApplyForce(ball, 10, 15) which would mean apply a force vector of (10, 15) to the object called ball.
So yeah in my physics processing i generally have some sort of system something like:
Do all collisions and physics checks to determine the forces being applied to every object. This could mean calling a function like the example I gave above quite a bit. Each object would have its own variable which keeps track of the forces it is subject to.
Then for each object:
Divide its force vector by its mass to determine the acceleration on the object for that frame.
Add the acceleration to the object's velocity.
Add the velocity to the object's displacement.
Reset the force variable so it can be recalculated in the next frame.

You can easily adapt that to work with moments, rotational velocity and rotational displacement as well.

metal
Quote:Original post by dgmul
Thanks for the help, oliii!

I think I'm beginning to understand that I really don't have to cheat as much as I initially thought I would - "locking" the ball into roll "mode" now doesn't seem to be necessary (er... I think).

I'm having a bit of a hard time comprehending all of the formulas in Chris Hecker's articles, though. Plus, I tried looking through your example code in C++, but the only language I know right now is Python and I'm having a bit of trouble trying to comprehend what your code does, especially with regards to the pointers.

Right now I've got a ball that just moves with a velocity, and I don't do anything with regards to mass, acceleration, or force, like in Chris Hecker's articles. I'm assuming that I should be implementing these things as well?


Fair enough. For a rigid body, here are the quantities I'd use at first.

// linear components
Vector position;
Vector linearVelocity;
float mass;

// angular components
float orientation;
float angularVelocity;
float inertia;

from this, you can do some simple rigid body physics.

for example, to apply a force {f}, at point of application {p}, for a time {t}

the velocity would become, after time {t}

linearVelocity += (f / mass) * t

the torque derived from the force and point of application would then be

torque = ((p - position) x f;

the angular velocity would then become

angularVelocity += (torque / inertia) * t;

And to update the position of an object, the Euler integration is simple

position += linearVelocity * t
orientation += angularVelocity * t

in short

struct rigidBody{    Vector m_position;    Vector m_linearVelocity;    float  m_mass;     float  m_orientation;    float  m_angularVelocity;    float  m_inertia;     // update position and velocity    void integrate(float dt)    {        m_position   += m_linearVelocity * dt;        m_orienation += m_angularVelocity * dt;    }    // apply acceleration at centre of gravity    void applyAcceleration(const Vector& g, float dt)    {        m_linearVelocity += g * dt;    }    // apply force at centre of gravity    void applyForce(const Vector& force, float dt)    {        Vector impulse = force * dt;        applyImpulse(impulse, m_position);    }    // apply force at point of application    void applyForce(const Vector& force, const Vector& point, float dt)    {        Vector impulse = force * dt;        applyImpulse(impulse, point);    }    // apply an impulse    void applyImpulse(const Vector& impulse, const Vector& point)    {        m_linearVelocity += impulse / m_mass;        m_angularVelocity += (point - m_position).crossProduct(impulse) / m_inertia;    }};


That is the basis of rigid body. TYo compute inertia for bodies, there are euqations on the web. It's quite simple, I think for a sphere the inertia is something like (radius^2 * 2/5) * mass.

For collisions, your collision report will return everything you need to compute the collision impulses at the points of contact. Then you apply the impulses.

As for the equations, I don't really know them in details, I just apply them.

if you ignore angular motion (i.e. change inverse inertia in the equations to 0), it is derived from those equations.

eq1) v1' = v1 + j / m1
eq2) v2' = v2 - j / m2
eq3) (v1' - v2') . n = -(cor) * (v1 - v2) . n

j : collision impulse (unknown)
v1, v2 : impact velocities
v1', v2' : resulting velocities (unknowns)
n : collision contact normal
cor : set coefficient of restitution (in range [0, 1]).

Then you should be able to arrive at an equation for j, that will be the same as mine/chris hecker equation, when you set inverse inertia to 0. Then it get a bit complicated.

Quote:
Also, I'm working with a moving ball interacting with static objects (such as walls and ramps), so shouldn't the formulas be slightly different in this case?

Peace and love,
dgm


The only difference with static bodies is that their mass and inertia are infinite (inverse mass = 0.0, inverse inertia = 0.0), and that their velocity is always 0, and they do not react when an external force is applied.

The equation can become simpler, but why bother make a special case. Having moving statics can be interesting, such as platforms, crushers, revolving doors. They have a linear and/or angular velocity, but their mass and inertia are still infinite (so they dont react with colliding with teh ball).

The equations are the same, which is quite neat. Storing the inverse quantites of mass and inertia can help you define static bodies (as inverse quantities are almost always used in rigid body equations).

EDIT : D'uh. impulse = force * dt;

[Edited by - oliii on August 1, 2008 8:22:04 AM]

Everything is better with Metal.

Wow! Thanks a lot, oliii. Your post & pseudo-code really helped me begin to understand this better.

I went back, and now I'm trying to go through Chris Hecker's collision response tutorial again. I've implemented Hecker's formula for calculation of the (frictionless) impulse, and it seems to be working rather nicely.

Here's how I have the impulse calculated:

pdot = (collisionPoint - centerOfMassPoint) x (collisionNormal)impulse = (-(1 + coefficientOfRestitution) * collisionNormal x linearVelocity) / (inverseMass + inverseInertia * pdot * pdot)


Of course, without friction implemented, the ball spin is not affected at all.

Where exactly might the friction coefficient be implemented?

Peace & love,
dgm
One thing you are not considering, is the velocity at the conatct point. Which is the linearVelocity plus the angular velocity x the contact point distance.

something like...

contactPointVelocity = linearVelocity + (collisionPoint - centerOfMassPoint).perp() * angularVelocity;

That's what you should use in the equation.

perp() returns the perpendicular vector. i.e. a.perp() = Vector(-a.y, a.x);

Note that in 3D, the angular velocity is a vector, and then you use a cross product instead of the perp function.

One way I implemented friction (through sheer laziness), was to apply the exact same function, but using a different collision normal. Basically, the friction normal is on the collision plane, going against the velocity at the contact point.

frictionNormal = contactPointVelocity - (contactPointVelocity . collisionNormal) * collisionNormal;
frictionNormal *= -1.0f;
frictionNormal.normalise();

pdot = (collisionPoint - centerOfMassPoint) x (frictionNormal)

frictionImpulse = (-(coefficientOfFriction) * frictionNormal . contactPointVelocity) / (inverseMass + inverseInertia * pdot * pdot)

Not sure if that is accurate or not. It seems reasonable but who knows :)

There is a limit to the amount of friction you can apply, which will be the magnitude of the collision impulse times a coefficient (the 'grip' if you will).

Everything is better with Metal.

Seems like a reasonable approach, oliii.

Now I think I see where you're getting at, metalmidget...

We just need to break up the new speed vector after the collision, into a tangential and a normal component (sort of like x and y, but rotated). We multiply the tangential component by the friction coefficient, and we multiply the normal component by the coefficient of restitution.

This shouldn't be too hard... I just want to think of an elegant way to implement it into the actual impulse formula rather than a sort of "hacky" way.


EDIT: Oh, by the way, just for clarification, is angular velocity measured as radians over time?
angular velocity is in radians per seconds.

Everything is better with Metal.

This topic is closed to new replies.

Advertisement