Sign in to follow this  

Timebased physics

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I'm just running into trouble with the physics in my Jump 'n' Run game. All the movements in the game are based on the time of the last frame, so is the gravity. But with the gravity I got the problem, that the simulation runs different on various machines. I think, that's because on a fast machine there are a lot more simulation steps calculated than on a slow one. For example I do jumping in my game by just setting the vertical velocity to a negative value. Then gravity is applied to the object every frame. On my computer the height of the jump is just right, but on a slower machine the player doesn't jump high enough. Any idea, how I can solve this problem? thx, fallen

Share this post


Link to post
Share on other sites
The solution to the problem is to use frame-rate-independent physics steps. Search the forum archives for keywords like "physics time step" and you should find several good old threads.

The basic idea is that you always use a constant time step, say 1/100 second, for your physics updates. Then, during the game, you do NOT update physics during a frame UNLESS more than 1/100 second has passed. When you do a physics update, you do as many physics updates as needed to catch up. Pseudo-code looks like this:


pts = physics time step = 0.01;
accumulated_frame_time = 0.0;

for (each frame)
{
accumulated_frame_time += current_time - previous frame time;
while (accumulated_frame_time > pts)
{
DoOnePhysicsStep(pts);
accumulated_frame_time -= pts;
}
}


That way, every time you render a frame, your physics will catch up, and the solution will be perfectly repeatable (for the same number of physics steps) on ANY machine. Now, you may be doing more than one physics step per frame, and there may be frames where you do zero physics steps, but you can be assured that the physics results will be machine independent.

Share this post


Link to post
Share on other sites
I have got problems of the same nature, in my case I have a constant acceleration: when it takes very short to render a frame, the new speed is calculated more often and the object moves faster over a set amount of time. But when it takes long to render a frame, the new speed is not calculated very often, and the object moves only a smaller distance at that same time.

So, if someone could help us out (same kind of problem), thanks beforehand. If the problem is not the same as the TS, please ignore this post, I'll start a serperate thread then.

--
Sijmen Mulder

Share this post


Link to post
Share on other sites
this is how you should do it if you are not already doing it like this for each frame:

acceleration = gravitational_constant (e.g. -10)
velocity += acceleration * frametime
position += velocity * frametime

[Edited by - SpaceDude on August 27, 2004 4:01:28 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by SpaceDude
this is how you should do it if you are not already doing it like this for each from:

acceleration = gravitational_constant (e.g. -10)
velocity += acceleration * frametime
position += velocity * frametime


That solution is not indipendent of the framerate, as I explained above.

Share this post


Link to post
Share on other sites
Quote:
Original post by SpaceDude
acceleration = gravitational_constant (e.g. -10)
velocity += acceleration * frametime
position += velocity * frametime
This is a common mistake. The problem is that there is some error and the amount of error depends on the frame rate. If you don't want to use a fixed time step (as suggested by grhodes_at_work), the following will give you the exact results for motion with constant acceleration (i.e. gravity).
t = duration of the last frame
a = acceleration
s = current position
v = current velocity

s += v*t + 0.5*a*t*t;
v += a*t;
Note: the order of execution is important -- the old velocity is used to compute the new position.

Share this post


Link to post
Share on other sites
Quote:
Original post by red_sodium
Or you could just multiply all your values by a function which returns the number of seconds passed (it would need to be a float) from last frame to this one. Then make all your values per second.


Isnt that whats just been shown as wrong?

Share this post


Link to post
Share on other sites
Quote:
Original post by JohnBolton
s += v*t + 0.5*a*t*t;
v += a*t; [/code] Note: the order of execution is important -- the old velocity is used to compute the new position.


Note that this works when gravity is the only acceleration. If you add in wind resistance or other things, this closed form solution dies!

Share this post


Link to post
Share on other sites
Quote:
Original post by JohnBolton
s += v*t + 0.5*a*t*t;
v += a*t; [/code] Note: the order of execution is important -- the old velocity is used to compute the new position.


Actually, my last reply was wrong. This works for any constant acceleration, and gravity happens to be an example. But, I disagree with the order. I say that v should be updated first, since it can be calculated exactly, and s calculated using the new value for v. Essentially, what JohnBolton did was write out the full Taylor Series expansion for distance (s) for a constant acceleration. Here, v is ds/dt (first derivative) and a is d2s/dt2 (second derivative). Since a is constant, there are no higher order terms (HOT) and so the expansion is complete with the second derivative. This is exact for a constant acceleration. The equation for v also is exact for constant acceleration. (t, of course, is the time step, not the actual time.)

You can also use these if acceleration is not constant; HOWEVER, what you are effectively doing is assuming acceleration is constant during a frame, which introduces discontinuities (abrupt and instantaneous changes) from frame-to-frame. Acceleration becomes a discontinuous step function. In reality you want to simulate a smooth variation from frame-to-frame.

Share this post


Link to post
Share on other sites
Quote:
Original post by grhodes_at_work
Quote:
Original post by JohnBolton
s += v*t + 0.5*a*t*t;
v += a*t;
Note: the order of execution is important -- the old velocity is used to compute the new position.


... But, I disagree with the order. I say that v should be updated first, since it can be calculated exactly, and s calculated using the new value for v. Essentially, what JohnBolton did was write out the full Taylor Series expansion for distance (s) for a constant acceleration...
The computation must use the old velocity in order to be exact. Actually, I'm not doing anything clever or using any mathematical manipulations. The equations for the position and velocity of an object moving with constant acceleration are these:
v = v0 + a*t
s = s0 + v0*t + 0.5*a*t2
where s0 and v0 are the initial position and velocity, and t is the total elapsed time.

At the end of an interval you compute values for s and v. These become the initial values for the next interval and t is reset to 0. Without simplification/optimization, it would look like this:
v = v0 + a*t
s = s0 + v0*t + 0.5*a*t2
v0 = v // Initial velocity for next frame
s0 = s // initial position for next frame
That makes sense, right? And it shows that the new position is computed with the initial velocity and not the new velocity, right?

[Edited by - JohnBolton on August 25, 2004 1:16:36 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by JohnBolton
That makes sense, right? And it shows that the new position is computed with the initial velocity and not the new velocity, right?


Well, yes, :), that does look correct! (That's what I get for thinking like a numerical analyst and not actually doing the math, eh?!)

Share this post


Link to post
Share on other sites
I have a similar problem with something I am working on at the moment. I am using a similar algorithm to the one that uses
frame-rate-independent physics steps as suggested by grhodes_at_work in an earlier post. I found this type of algorithm worked with my collision detection system, whilst using a multiplier did not since the objects became so fast that they passed right through the walls. Using steps allowed me to calculate where exactly the object collided.

The new problem I have is this:-

I have been using the last frame time to calculate the number of time steps for what I shall call the current frame. Unfortunately the current frame sometimes takes a different amount of time to draw than the previous. This causes a visible jerk in the physics update. For example if the last frame time is 16 ms, and I want to tick twice per 60th of a second, then the update function is called twice - however if the current frame has a massive amount of polygons in the viewing frustrum the current frame takes up to 24ms to render ... thus I have ticked the wrong number of times. I have tried using average values to guess the next time, but it still jerks a bit.

Can anyone please help with a method of smoothing the time predicted for the next frame that can fix the bug?

I have been working on this idea for over a month and I still don't have a completely satisfactory solution.

Share this post


Link to post
Share on other sites
hmmm, ...that should not matter at all. The frame timestep is the measure between the start of two game updates. You'll see slow downs when your render gets sluggish, but that's innevitable. As long as with frame rates above 20hz, you do not see any random acceleration or slow downs of the game or lags in the controls, when all will be fine. Under 20 hz, it's hard to actually see discrepancies like that.

The downside of performing several physics updates per frame like that, is that, the worst the frame rate, the more work you will be doing, which can potentially slow down the frame rate, ect... But keeping the framerate in check should be a dynamic process.


void UpdateAndRender()
{
t(++i) = time();
dt = t(i) - t(i-1);
Update(dt);
Render();
}

void Update(float t)
{
const float timestep = 1.0f / (2.0f * 60.0f);
float num_updates = ceil(t / timestep);
float dt = t / num_updates;

while (t > 1.0E-6f)
{
t -= dt;
UpdatePhysics(dt);
}
}



how does that look?

Share this post


Link to post
Share on other sites
Hi,

the algorithm looks fine, but I still have problems with the Rendering time change. I think I might need to lock the framerate to a value defined by the users pc or platform, then use the discrete times stepping method to compute the physics. That should ensure that the percieved speed is the same on different systems.

thanks.








Share this post


Link to post
Share on other sites
As long as you perform enough physics updates to keep up with (or slow down to) the actual rendering frame rate, objects will be moving at the same speed, even on different hardware! Granted, the rendering might not actually render the same exact frames, but the physics will be the same and the object speeds and motion paths will be the same. If you are concerned about rendering the same frames, well, I think you're worrying too much. There are some simulation systems that need to do this, but in my opinion entertainment gaming does not require this. As long as you have reasonably good frame rates, maybe even just 30fps or better, things should look just fine and you don't need to worry about it.

That said, if you're doing a networked multiplayer game, you do have other issues to deal with, such as....does each machine compute the physics for the entire world, or only things that are local to the player on a given machine? Probably the latter, but then with multiple machines calculating physics and the network traffic responding at yet a different rate of update (that is different from the physics step size and the render frame rate) you have to figure out how to extrapolate motion for objects that are being physically simulated on another computer (dead reckoning), etc. When you get down to it, not all that trivial of a problem.

Share this post


Link to post
Share on other sites
Quote:
Original post by JohnBolton
Quote:
Original post by SpaceDude
acceleration = gravitational_constant (e.g. -10)
velocity += acceleration * frametime
position += velocity * frametime
This is a common mistake. The problem is that there is some error and the amount of error depends on the frame rate. If you don't want to use a fixed time step (as suggested by grhodes_at_work), the following will give you the exact results for motion with constant acceleration (i.e. gravity).
t = duration of the last frame
a = acceleration
s = current position
v = current velocity

s += v*t + 0.5*a*t*t;
v += a*t;
Note: the order of execution is important -- the old velocity is used to compute the new position.


Its not a mistake, i have done it like this intentionally. Ok your solution is 100% accurate for something really simple like an object with constant acceleration that won't ever colide with anything. But what kind of boring game would that be ? :)

As soon as you start to make things interesting like having non-constant accelerations and objects colliding. Your solution will no longer be accurate. So you've got errors no matter what you do.

So to keep things simple I just assume that we have constant accerlation and constant velocity during each frame. The error is fairly small anyway with frame rates above 30. I mean it just isn't practical to do swept sphere collision taking into account acceleration, its already complicated enough without worrying about that.

Ok so you could come up with a way of using your formula when there is no collision and then use the simplified version when there is collision.

But at the end of the day, if you can't simulate something perfectly. Then you've got to just minimise your errors. And there is no point in complicating something to eliminate an error which is insignificant compared to others. You're just increasing the chances of you making a mistake and spending hours trying to debug it.

Obviously, it depends on the game. All that i was trying to point out is that you need to take into account the time from last frame, or your results will be completely wrong (get things moving twice as fast on a machine with twice the frame rate).

Share this post


Link to post
Share on other sites
I have to agree with grhodes here,

What I have done was simple,
just a rough class


class Player
{
Vector3 vel; //XYZ
Vector3 pos; //XYZ
float mass; //in Kg
}

//the seconds would usually be like 0.003153 etc
public void KeyPress(float TimeElapsed) //in seconds
{
float force = 60; //just a variable for this example
//force in Newtons
if (Right) //psuedo code for "if it's right"
{
vel.X += (force/mass)*TimeElapsed;
}
... other keys here
}
//I used a = F/m as defination for accel.

//after this function is called all objects get updated to apply the laws of physics

public void TranslatePositions(float TimeElapsed)
{
pos.X += vel.X * TimeElapsed;
... for other vector directions too
}


that works for me just fine...

Share this post


Link to post
Share on other sites
Quote:
Original post by SpaceDude
Its not a mistake, i have done it like this intentionally...


The thing is that both The_Fallen and Sijmen said that their problem was that the path of falling objects was different for different frame rates, and both included frame durations in the calculation. It is very common for people to implement falling objects using your solution and then pull their hair out because it is still framerate-dependent. That's why I said it was a mistake -- because usually it is.

It is so obvious to me that the frame duration must be included that I didn't consider that it might not be obvious to someone else, and I missed the point of your post. Sorry.

Share this post


Link to post
Share on other sites

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

If you intended to correct an error in the post then please contact us.

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