5
\$\begingroup\$

I've got a projectile working perfectly using the code below:

//initialised in loading screen 60 is the FPS - projectilEposition and velocity are Vector3 types

gravity = new Vector3(0, -(float)9.81 / 60, 0);
//called every frame
projectilePosition += projectileVelocity;

This seems to work fine but I've noticed in various projectile examples I've seen that the elapsedtime per update is taken into account. What's the difference between the two and how can I convert the above to take into account the elapsedtime? (I'm using XNA - do I use ElapsedTime.TotalSeconds or TotalMilliseconds)?

Edit: Forgot to add my attempt at using elapsedtime, which seemed to break the physics:

projectileVelocity.Y += -(float)((9.81 * gameTime.ElapsedGameTime.TotalSeconds * gameTime.ElapsedGameTime.TotalSeconds) * 0.5f);

Thanks for the help

\$\endgroup\$

4 Answers 4

5
\$\begingroup\$

If you assume a constant frame rate of 60, your game doesn't work with the same speed with any other frame rate. If your rendering is too slow, the physics will also slow down. Sometimes this is desirable, but usually games are running the physics with constant speed independent of the rendering frame rate.

You can change your formulas to use elapsed time instead of 60, but it is very hard to do that in a way that the physics will behave the same with different time differences. For linear movement it is not a problem, but already for a parabolic trajectory or collisions this becomes hard and for more complex trajectories there is no closed form formula.

The best solution usually is to use frame skipping. In this approach you take the elapsed time into account, but instead of updating the formulas you calculate how many times you need to update the physics in a row. This means that if the rendering is lagging, the physics will be updated several times per rendering frame. If the rendering is running faster than the physics should be updated, then frame skipping will skip the physics update as needed. The following code snippet does frame skpping. It assumes that the time units are in milliseconds, but it is easily adaptable to other units as well.

int TIMESTEP = 1000 / 60; // 1000 milliseconds in second, 60 Hz physics update
long previousTime = getTime();
long deltaTime = 0;

while (gameRunning) {
    long currentTime = getTime();
    deltaTime += currentTime - previousTime;
    while (deltaTime >= TIMESTEP) {
        updatePhysics();
        deltaTime -= TIMESTEP;
    }

    render();
}
\$\endgroup\$
2
  • \$\begingroup\$ This may seem a little obvious, but what time are you retrieving with getTime()? \$\endgroup\$ Jun 25, 2015 at 23:31
  • 1
    \$\begingroup\$ @cossacksman Milliseconds since something. The origin of the time is irrelevant, as we are only interested about difference between two time points. \$\endgroup\$
    – msell
    Jun 26, 2015 at 5:02
2
\$\begingroup\$

Your formula is wrong, as 0.5*accel*t^2 gives a change in position, not a change in velocity. What you probably want to do is this:

gravity = new Vector3(0, -9.81f, 0);
projectileVelocity += gravity * gameTime.ElapsedGameTime.TotalSeconds;
projectilePosition += projectileVelocity * gameTime.ElapsedGameTime.TotalSeconds;

Note that the framerate of 60 is not needed, this will work for any framerate which is the main reason to use elapsed time in the first place.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks for the correction. One thing I don't understand is that s = ut + 0.5at^2. Where does the 0.5 aspect go in your code? (Not saying it's wrong, just wondering). (edit: I'll upvote when I have enough points) \$\endgroup\$
    – XSL
    Mar 9, 2011 at 4:02
  • \$\begingroup\$ My code isn't using that formula. The time 't' in s=ut+0.5at^2 is the total time since the projectile launched, not the elapsed time. Similarly the 'u' is the initial velocity, not the current velocity. My code is doing Euler integration, using the elapsed time since the last frame. First it integrates the current velocity with v += at, then it integrates the position with p += vt. \$\endgroup\$
    – Niall
    Mar 10, 2011 at 1:49
0
\$\begingroup\$

What you are doing is actually the starting point of what quite a few physics packages do, and that is used a fixed time step for your updates. By dividing the value by 60 you are using a fixed time step.

What using the elapsed time would do is allow that to happen even when you are Not running at 60fps. You would use the actual elapsed time instead of 1/60.

As for the error to why your switching didn't work as expected is I believe because you are using TotalSeconds.. Which is probably the number of seconds your game has been running instead of the number of seconds since the last frame update. Aside from that it looks like

\$\endgroup\$
1
  • 2
    \$\begingroup\$ The TotalSeconds is the number of seconds since the last frame update since he's using ElapsedGameTime.TotalSeconds and not TotalGameTime.TotalSeconds \$\endgroup\$
    – Ray Dey
    Mar 7, 2011 at 18:19
0
\$\begingroup\$

You could try to do more accurate integration. What you have is called the Euler method, and you have to use really small times steps to make it accurate. The next best method is to evaluate the acceleration at the beginning and end of the time step, i.e. compute the acceration at time t0, then advance at that velocity and acceleration by delta T. Then recalculate velocity/acceleration at that time step. Now take the average of the two, to advance from to to t0+dt. This is second order accurate rather than first, so errors won't accumulate nearly as fast.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .