Gravity (not so simple)

Started by
6 comments, last by Asphyxia 19 years, 11 months ago
Although this looks like a write-up at first, it''s really a question but it needs to be specific. Excuse the length of the post... A lot of game demos that show the use of gravity will simply invert an objects y-axis velocity when the object hits the "ground" if they want it to bounce back up...

#define PIXELS_PER_METER 300
#define GRAVITY (9.8 * PIXELS_PER_METER) / 100
#define APPROX_GRAVITY (10 * PIXELS_PER_METER) / 100

object.y += object.vy;
if(object.y + object.height > screen_height)
{
	object.y = screen_height - object.height;
	object.vy = -object.vy;
}

object.vy += APPROX_GRAVITY * last_frame_time;
This is all fine and good (and usually best) for most situations, but in terms of more realistic physics simulation I see this as incorrect for three reasons. One, in real life, an object hits the ground and bounces back up. In the code situation the object falls into the ground, is instantly repositioned at ground level, and then is bounced back up. Two, the code example assumes perfect elasticity (not too big of a deal) so, when the object is bounced back up, it goes back in the "air" with the same energy it hit the ground with. Three, because the object was repositioned and restitution isn''t taken into consideration, the object should actually going back in the air with MORE energy than what it hit the ground with. It adding restitution is easy, simply "absorb" some of the energy of the object when it hits the ground...

object.cor = .92; // coefficient of restitution (bounciness)

/*
... some code here ...
*/

object.vy = -object.vy * object.cor;

So that takes care of number 2 and part of number 3. Now, to adjust the object''s energy so it hits the ground instead of falling into the ground, the objects velocity needs to be adjusted to negate the extra energy it gained while falling into the ground. To do this some information is needed... the objects current velocity (object.vy), its speed of acceleration (APPROX_GRAVITY * last_frame_time), and the distance the object fell into the ground (object.y + object.height - screen_height). Here is where I''m sure I messed up my calculations... To calculate the extra velocity gained while falling into the ground, I used the kinematic equation for velocity after acceleration over a distance... Vfinal^2 = Vinitial^2 + 2*Acceleration * Distance

float
	vf, // Vfinal

	va, // Vadjusted

	vi, // Vinitial

	accel, dist;

vi = object.vy * object.cor;
accel = GRAVITY;
dist = (object.y + object.height) - screen_height;
vf = sqrt((vi*vi) + 2 * accel + dist);
va = vf - (vf - vi);
object.vy = -va;

object.y = screen_height - object.height;
While this seems correct at the moment, when the energy of the object gets extremely low, the energy from the bouncing and gravity begins to fluctuate (the object''s energy never gets low enough that it stops "dribbling"). Right now I''m attributing this to either not enough accuracy in the gravity constant or timer (GetTickCount()), or to an error in the calculation. Any ideas? This shouldn''t be hard to turn into real code but if someone feels the actual source code is needed, I can make it available.
Advertisement
I don''t understand your 3rd point.
How does the object get extra energy with just negating the velocity? E = m * v^2; v is negated, so E does not change.
When it reaches the initial height, it will have the same velocity as earlier at this height.
I think the energy absorbed could be: Ea = a*v^2 + b*v + c; a,b,c are well-chosen coefficients.
Doing so the energy can become exactly zero, and thus the object stops, doesn''t fluctuate.
as a hopefully useful aside, GetTickCount() is only accurate to within 10ms i think. you want to be using QueryPerformanceCounter & QueryPerformanceFrequency (look em up on msdn for usage)

-me
I understand your third point, as the object "skips" through the object, it''s velocity will be higher than when it actually made contact with the object.

As for your problem with the decay of the ball height, in theoretical terms without any additional resistance to motion, the ball will never stop bouncing. It''s energy can never be completely dissipated so the height of bounce will decay reaching zero only as time approaches infinity.

The easiest way round the problem is to simply insert a conditional if to find when h is very small and just zero it.

the problem lies in the fact (if i see it correctly) that the velocity you take when inverting is the velocity at the end of the time step.
Because the ball has gone virtually through the floor it gained velocity because of g over the distance travelled beyond the floor. This velocity needs to be subtracted and also the remaining time left needs to be taken in to account to place the ball at the correct position. it bounced and went up in the timestep.

the dribbling comes from if i see it correctly that the force g pulls the object through the floor and then you reposition it. Make sure that when the velocity is small enough to apply a normal force to the ball that cancels the gravitational force.
* Addition to my previous post *
When I say zero it, I mean both the velocity and height!
I see what you mean, the kinetical energy will be higher than if you would have reversed the velocity when you actually hit the ground, then you move the object up, thus increasing the potential energy without decreasing the kinetical energy.

So basicly, i guess you will have to do just that. Check the how far below the screen the object is, convert this to kinetical energy (movement) and subtract it from vx.

----------------------------
When hell freezes over it will be a pretty cool place to snowboard
quote:Original post by Airo
... the remaining time left needs to be taken in to account to place the ball at the correct position. it bounced and went up in the timestep.


Nice point! I actually did completely forget that time was also a part of the equation.

This topic is closed to new replies.

Advertisement