Smooth timestep transition

Greetings everyone.
Trying to implement a fixed timestep in my code i want to achieve smooth movement for my objects (basically on neko). The problem is that the movement is kinda jerky on bitmaps. I tried with tilemap and got the same result. I tested a lot and i saw that the delta time is not always steady just 1 bitmap onscreen. I studied a lot of posts, trying to find something similar and figure out the problem by myself but i could not find a decent solution. Maybe somebody can help me out with that?

Have you tried using Actuate?

Actuate.tween (sprite, 2, { x: 300 });

This code will tween an object named “sprite” from it’s current position to an x of 300 over 2 seconds, using an exponential ease out equation. This will use a linear (consistent) equation:

Actuate.tween (sprite, 2, { x: 300 }).ease (Linear.easeNone);

The best result comes from using a mixture of ENTER_FRAME as well as time elapsed to adjust the animation based on how much time has passed since the last frame. That’s what Actuate does, and though you don’t have to use Actuate, it’s a simple way to get started :smile:

Thanks you for the reply!
Basically i need a timestep for a game. I already have a basic framebuffer and i draw everything there (i read the post using a texture framebuffer, thats brilliant news). So calculating delta by using ENTER_FRAME, instead of using a timer will have better results? I will check actuate as well. :slight_smile:

You’ll want a combo, basically, you render only on ENTER_FRAME, but you compare Lib.getTimer between frames to determine the delta :smile:

Yeah, that’s what i do. But the movement is still kinda jerky and i clearly see that the delta is not stable all the time. I though that my computer was the problem but it’s not. I increased the framerate on the project, tried to turn v sync on, but nothing… Maybe something i miss? I used to have a similar problem when i used AS3, so i dont even bother building for Flash but though that it would be much smoother on native targets.

What is your FPS? How are you calculating delta time? Just for the case you don’t know this (you probably do), you need to compute on every frame (ENTER_FRAME event), how much time has passed since last frame (for example difference of two Sys.time() and then shift everything by correct amount). Delta time will be different on every frame, you can’t expect it to remain constant, it will never be.

Basically,

velocity = distance / time

so if you want velocity to remain constant and time difference is always changing, you need to compensate distance moved every frame.

Maybe its pixel snapping problem?

My mistake, i should have showed the code before ask for help. The code for the delta is as basic as it gets…

_time = Lib.getTimer();
_delta += (_time - _last);
_last = _time;

while (_delta >= _rate)
{
        update(delta);
}

render();

I used the openfl.Timer at first, not the haxe.Timer event. Tested the same thing on ENTER_FRAME and haxe.Timer and got much better results. I tried on a different computer as well and it plays nice. Just for the info, what about pixelsnapping?

Thanks everyone for your help.

I’m not sure, if I’m explaining this right, but basically if you (or something else) force pixels to integer positions on every frame, it could pose a problem for obvious reasons.

I assume there’s a line that says _delta -= _rate somewhere in update()?

Also, shouldn’t it be update(_rate)?

Sure there is _delta -= _ratein the end of the function. As far as i know, i always used update(_rate * _delta) for the update. Am i not aware of something? Rendering on the other hand should occur on every enter frame, with no limitations but the tick of entering every frame.

Let’s walk through what happens during a frame, step by step. We’ll assume _rate is 0.04, and that each frame takes exactly 0.11 seconds.

Frame 1:

  • Add 0.11 to _delta.
  • _delta is now 0.11.
  • Enter while loop, because 0.11 >= 0.04.
    • Call update(_delta).
    • Subtract 0.04 from _delta.
    • _delta is now 0.07.
  • Repeat while loop, because 0.07 >= 0.04.
    • Call update(_delta).
    • Subtract 0.04 from _delta.
    • _delta is now 0.03.
  • End while loop, because 0.03 < 0.04.

Frame 1 results: update(_delta) was called twice this frame, with the following values: 0.11, 0.07. These add to 0.18, so we did the equivalent of update(0.18) for a frame that lasted 0.11 seconds.

Frame 2:

  • Add 0.11 to _delta.
  • _delta is now 0.14.
  • Enter while loop, because 0.14 >= 0.04.
    • Call update(_delta).
    • Subtract 0.04 from _delta.
    • _delta is now 0.1.
  • Repeat while loop, because 0.1 >= 0.04.
    • Call update(_delta).
    • Subtract 0.04 from _delta.
    • _delta is now 0.06.
  • Repeat while loop, because 0.06 >= 0.04.
    • Call update(_delta).
    • Subtract 0.04 from _delta.
    • _delta is now 0.02.
  • End while loop, because 0.02 < 0.04.

Frame 2 results: update(_delta) was called three times this frame, with the following values: 0.14, 0.1, 0.06. These add to 0.3, so we did the equivalent of update(0.3) for a frame that lasted 0.11 seconds.

As you can see, in both cases, the time passed to update() was much greater than the actual time elapsed. But all that means is your game will run fast, not that it will stutter. The reason it stutters is because frame 2 ran update() for almost twice as long as frame 1 (0.3 seconds vs. 0.18 seconds). This means that objects will move almost twice as far on some frames as they do on others.


Now let’s see what happens if you call update(_rate) instead of update(_delta). The while loop is unaffected, so I won’t bother typing all that out again. The only difference is that each iteration of the loop calls update(0.04) rather than a varying value.

Frame 1: two update(0.04) calls. Total: 0.08 seconds.

Frame 2: three update(0.04) calls. Total: 0.12 seconds.

Much better, wouldn’t you say? Not only is update() being run for about the right amount of time, there’s a smaller difference between the frames.

2 Likes

Player_03 you are right, thanks for your great help and guidance. I could not have a better example but the way you described it, thanks a lot. I implemented right away but i am kinda like to break things apart to learn and study. Thanks for making it easier for me.

I think your alternative would be update(_delta) once per-frame, and not calling it within a loop. Then “Frame 1” is 0.11, and “Frame 2” is 0.11, but it depends on how you want to treat your logic, the way you are handling it now (with a fixed time-step) may work better with physics, but be careful if a user sends the application to the background and resumes it, your delta might be an order of magnitude larger and freeze up :smile: