[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Fwd: Stuck in a ball's velocity vector -.-



Yet another formulation (without involving angles at all).

[this turned out a bit long, hope someone has the energy to read it]

Assume the objects are touching along a plane (a line in 2d). Call the
normal vector to this plane "n". You have to calculate the n
differently depending on what kind of objects you are colliding, but
for circles n is always a vector between the center of the two
circles. For circle/wall collisions the collision normal is always the
normal of the wall. Note that the collision normal is not dependent on
the object velocities, only on the object position!

Now, if we disregard friction, all forces on the objects have to be
along the direction of n, so now we just have to calculate the
magnitude of the force. According to Newton's third law: "All forces
occur in pairs, and these two forces are equal in magnitude and
opposite in direction.", which means that the same force, with
opposite signs, will work on both the bodies in the collision. if F1
(a vector) is the force acting on object 1 and F2 (another vector) the
force on object 2 we now have

  F1 = -F2  (Newton III)
  F1 = a*n (by the assumption that the force has to be along n)

Were a is a scalar, the magnitude of the force. Here people have very
different opinions on how to calculate a.

For simple elastic collision with equal mass objects you do reflect
the ball velocities using the n vector (assume it is normalized
below).

For each ball, do v_new = v_old - 2*dot(v_old,n)*n, where dot(a,b) is
the vector dot product and v is the velocity vector. This is generally
how you reflect vectors, but remember that n has to be normalized
here.

In the more general case I like to do it like this:

Assume the collision is short, and we want to find the impulse I
(total force over time) that makes the objects bounce off each other.
In a completely elastic collision no energy is lost, and in a
completely inelastic collision the maximum energy is lost. Let's write
down the kinetic energy before and after the collision (without the
factor 1/2 for simplification):

Ebefore  = m1*v1^2 + m2*v2^2
Eafter = m1*(v1 + I/m1)^2 + m2*(v2 - I/m2)^2

Now, the energy difference is
Ediff = Eafter - Ebefore = 2*dot(v1,I) - 2*dot(v2,I) + I^2/m1 + I^2/m2

We see that the energy difference is a quadratic function in the
magnitude of the impulse I. Remember that the forces had to be along
the collision normal n, so lets put in I = a*n with n normalized and
simplify a bit:

Ediff = 2*dot(v1-v2,n)*a + (1/m1 + 1/m2)*a^2.

There are two values of a for which the energy is conserved; one is a
= 0, which corresponds to no force at all, but the other one is more
interesting.

a_elastic = 2*dot(v1-v2,n)/(1/m1 + 1/m2)

This is the impulse magnitude for a completely inelastic collision. We
can see that it depends of the difference of the objects velocities in
the direction of the collision normal.
We can also minimize Ediff to get the maximally inelastic a, IIRC
a_inelastic = a_elastic/2.
Now we can put in any a between a_inelastic and a_elastic if we want
to have some energy  loss in the collisions.

I like this approach because you never need to calculate any angles or
use trigonometric functions. just

1) Obtain collision normal n
2) Calculate a_elastic from the formula above
3) scale it down with a factor between 0.5 and 1 to get inelastic collisions
4) Change the object velocities by a*n/m1 (object 1) and -a*n/m2 (object 2).

I wrote this from memory, so there might be some small mistakes
somewhere, but there will be a small example program using this
approach released together with the next pygame version.

Regards,
Ulf