Delta time movement calculation

Started by
19 comments, last by rip-off 8 years, 3 months ago
http://gafferongames.com/game-physics/fix-your-timestep/

Your problem is that 0.13 delta time. 0.13 seconds means that you're running below 10 frames per second. Most game math will completely break down and stop working as intended somewhere around 15 frames per second because of the exact thing you're seeing - calculations based on time get blown out to unacceptably large numbers. Physics tunneling and all sorts of other problems become far, far more likely, which I'm assuming is what you mean by "break your objects' positions."

Fixing your time step, as the link explains, avoids this problem. Because you'll do your movements at a fixed time step and then only use delta time to calculate the number of time steps you should run each frame. This doesn't _completely_ solve all problems associated with a low frame rate, but it avoids the worst of the game logic bugs.

You really should figure out why your frame time is so horrendous on that Xperia tablet, though. Your absolute maximum frame time should be around 0.033 seconds (30 FPS).

Another technique many games use is to clamp the delta time at a value of around 0.05 (20 FPS), so if the hardware is running slow the result is that the whole game just runs slower. This will often give you far better results even if you've fixed your time step (as it helps to avoid the "spiral of death" problem where a long frame results in more fixed timesteps being run the next frame, which causes that frame to take longer, and then the cycle repeats).

Sean Middleditch – Game Systems Engineer – Join my team!

Advertisement

I'm sorry but I can't understand this link you refered. Maybe I'm dumb, but I've seen this page so many times and still didn't get it. Don't you have any explanations/tutorials for obtuse people like me?

My delta is calculated as,

float deltaTime = (timeSinceStart - oldTimeSinceStart) / 1000000000; //in order to get it in seconds

Device framerate is about ~30fps (tablet), 25fps on my very old Galaxy ace S5830i and about 70-80fps on Xperia.

When do you set 'oldTimeSinceStart'? It could be that you initialise it in your constructor, then you do a few other things (which takes time) and then finally you start your rendering, at which point a significant amount of time might have passed. That may cause a large delta value for the first frame (causing your object to jump) but then on subsequent frames the delta time is normal.

By displacement I meant distance, I'll edit my first post.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

I'm sorry but I can't understand this link you refered. Maybe I'm dumb, but I've seen this page so many times and still didn't get it. Don't you have any explanations/tutorials for obtuse people like me?

Simple version:

Don't use delta time for any game logic or movement. Always run logic with a fixed time step; something you pick like say 60fps (0.016 seconds). Use delta time only to calculate how many of these fixed time steps to run each frame.

// BAD
Update(deltaTime);

Draw();
// GOOD
maxDeltaTime = 0.1; // 10 FPS
fixedTime = 0.016; // 60 FPS

deltaTime = min(deltaTime, maxDeltaTime);

accumulatedTime += deltaTime;
while (accumulatdTime >= fixedTime) {
    accumulatedTime -= fixedTime;

    Update(fixedTime);
}

Draw();

All of your movement is calculated in some part of Update(time) or a callee of that function, so the only time value that you're ever working with is fixedTime. Thus your movement is effectively calculated as (screenWidth/2)*fixedTime. Since your two tablets have the same resolution, they will always move the exact same number of pixels on every logic update.

The only difference will be that a fast tablet will run logic once per frame and a slow tablet may run it several times per frame.

Device framerate is about ~30fps (tablet), 25fps on my very old Galaxy ace S5830i and about 70-80fps on Xperia.


Your frametime is not 80fps on the Xperia, assuming the numbers you gave originally are correct. You said the deltaTime on your Xperia is about 0.134 seconds. 1 frame / 0.134 seconds = 7 frames per second.

For the other tablet you said your deltaTime is about 0.33 seconds. 1 frame / 0.033 seconds = 30 frames per second, which sounds like what you're getting.

In order to have 80fps, you would need 1 frame / 80fps = 0.0125 seconds.

If your Xperia is supposedly running at 80fps and you're getting a deltaTime of 0.134, something is very very wrong with your timers, because the math doesn't work that way.

Sean Middleditch – Game Systems Engineer – Join my team!

Thank you SeanMiddleditch

I've read and understand much more from your writing, than from posted link. On A7600-F tablet it seems it's running perfectly, although it reachs distance in one second lower than it should (from distance calculation (screenWidth /4) * fixedTime). //I've edited divide a little bit

//Now with 4, it reaches whole screen width in 3 seconds. With 2, it was reaching screen width in 1 second.

On my old gold Ace, it runs very slow, but that's probably problem of whole phone, because it's framerate is very low on today's phones hardware (and it cannot reach at least 30fps, and target 60fps at all). It runs smoothly, but with periodical lag spikes. But I don't take this device seriously about games because of it's "age".

I'll try two more phones later today.

By the way, in your code is "Update(fixedTime);", I think it shouldn't matter if I make distance calculation before update or right in it, because there are just constant values, right? Because I'm calling only Update(); at the moment. (Just to be sure smile.png )

By the way, in your code is "Update(fixedTime);", I think it shouldn't matter if I make distance calculation before update or right in it, because there are just constant values, right? Because I'm calling only Update(); at the moment. (Just to be sure )


I recommend having some function that is the main entry point for _all_ such calculations, and not filling up that loop with unnecessary cruft. Keep your code simple and break things down into functions. You should ideally for a simple game have something like:

Update(float time) {
  UpdatePhysics(time);
  UpdateAI(time);
  UpdateEtc(time);
}
Definitely have only a single Update function called by the main timer loop. That gives you any number of advantages; my favorite one being that you can add debug pause and debug step features to the game which can be incredibly handy, esp. for physics debugging.

Sean Middleditch – Game Systems Engineer – Join my team!

You also want to make sure you lose minimum numerical precision when accumulating delta time values. This, and this (the timing section) should help a little.

Okay tested currently available devices to me. I can't test A7600-F tablet and Xperia Z3 Compact phone right now, but tested these devices:

Galaxy S - Android 2.3.3

- game running correctly.

old Galaxy Ace - Android 2.3.6

- I'm getting periodical lags here (about each half second) - same as in S3 mini. I don't think it's HW issue.

S3 Mini - Android 4.1.2

- problem too, I'm getting there periodical lags - but it must be doing something in code, because this phone is newest from these two's and is perceptible faster. I'm getting same lags about each half second.

But every phone of these three has +- same objects speed as others, so that's great! Just that "lagging"...

Currently I have this. As I said it doing periodical "lags" each 1/2 second (in same intervals and same lenghts).


/* Time vars */
private float oldTimeSinceStart = 0;
private float accumulatedTime = 0;
private float maxDeltaTime = 0.1f; // 10 FPS
private float fixedTime = 0.016f; // 60 FPS
/*   - - - - -   */


public MainThread(SurfaceHolder surfaceHolder, GamePanel gamePanel)
{
    super();
    this.surfaceHolder = surfaceHolder;
    this.gamePanel = gamePanel;
}


@Override
public void run()
{   
    while (running)
    {
    
        try
        {
            canvas = null;
            canvas = this.surfaceHolder.lockCanvas();

            synchronized (surfaceHolder)
            {

                float timeSinceStart = System.nanoTime();
                float deltaTime = (timeSinceStart - oldTimeSinceStart) / 1000000000;
                oldTimeSinceStart = timeSinceStart;

              
                deltaTime = Math.min(deltaTime, maxDeltaTime);


                accumulatedTime += deltaTime;

                while (accumulatedTime >= fixedTime)
                {
                    accumulatedTime -= fixedTime;

                    this.gamePanel.update();  
                }
  
                this.gamePanel.draw(canvas);

            }
        } catch (Exception e) {}

        finally
        {
            if(canvas!=null)
            {
                try
                {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
                catch (Exception e) {}
            }
        } 
    }
}

In the code where this.gamePanel.update() is, I didn't found a solution how to update game objects with time (as you wrote -
Update(float time) {
UpdatePhysics(time);
UpdateAI(time);
UpdateEtc(time);

}

so I let it like this). Its strange about these lags on phones (it doing more than on two's I've wrote), could you please check if everything above is okay? :/ .

bump

This topic is closed to new replies.

Advertisement