Fixed time step clarifications

Started by
3 comments, last by larsbutler 8 years, 1 month ago

<removed>

Advertisement

It is only really a concern for anything that requires time elapsed. Physics is a great example, if an object is falling at 1m/s and your render takes 1 second then you need to move the object by 1 meter (1x1). If the render frame took 3 seconds you need to move the object 3 meters (1x3). Usually you would do just that (speed*time) but when you get highly varied time segments then many things start to break down and not work correctly. With a fixed time step (lets say 1 second) then instead of doing an update with 3 seconds of elapsed time you do 3 separate updates of 1 second each. That way the update is always predictable/deterministic and doesn't break down with really short frames or really long ones.

I haven't tried using the interpolation route myself but it works by calculating a state in the future. For example at t = 0 your object object might be at (0, 0), it is moving +x 1 m/s. Say you have a time step of 1 second, what do you do at t = 0.5? The easiest approach is to just leave the state as it was at time 0 (until it gets to 1 of course), with high frame/tick rate people probably won't notice. The other option is to work out the next state anyway, the future state will then be t = 1 (1, 0).

Now you have 2 states, t=0 (0, 0) and t=1 (1, 0) but you are at t = 0.5 so you interpolate between those states which gives you (0.5, 0). That sounds like a lot and I haven't tried it myself but you wouldn't have to interpolate everything, just things that are relevant to how the user sees the world (mostly position).

As for dealing with network data coming in I certainly have no experience with and it depends how you are dealing with it. You could carry on doing it as you are and when you receive data package it up into an event and sent that event. Part of your update function would be processing any pending events so it would be picked up there and deal with appropriately during that time step. As I say, I have no experience with that regard.

I found this page useful:

http://gafferongames.com/game-physics/fix-your-timestep/

It was the first time I really 'got' it.

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

You can just lag by one frame and interpolate with the previous instead of trying to predict. After all, the "prediction" is really just doing a bunch of the next frame's work.

Networking isn't really any more or less of an issue. If you're using silly-long update intervals then the buffer could get full, but there's usually no reason for that. You may think of networking asynchronously (ugh...), but you don't get data from the NIC until you call the read function.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

to port to fixed timestep (a la gaffer):

1. modify your update to take float ET (in seconds) as an input parameter - where ET is how long the last render took.

2. modify all necessary data structures to hold both current and previous position and orientation of all moving renderable objects.

3. the amount of game time your update is supposed to represent is the value DT. for 30 updates per sec, this would be 33ms, and so on.

4. in update: divide ET by DT, this is the number of times to run update this time through the loop. store the remainder.

5. in update, store both the previous and newly calculated current locations and orientations.

6. in render, tween between previous and current, by the amount remainder / DT, and use that location and orientation to draw.

not a lot of work, but not trivial either, depending on the complexity of your render and update routines.

note that this algo does not degrade gracefully if ET goes high. if ET >= DT*2, it will drop frames (still run updates, but not render them) to try to keep up. so FPS tanks and the game starts doing more than one update per render, all at once. can make the game unplayable if ET is high enough. if needed, an ET cap can be used to avoid this. the cap can be used to avoid more than one update per render, so render and update slow down uniformly under heavy graphics loads.

also note that this algo does not draw objects in their current location, instead it draws them where they were ET%DT seconds ago. so if DT is 33ms (30 updates per sec), and ET is 16ms (60 FPS), then on average it will draw objects where they were about 16ms ago. odds are anything in a game moving fast enough that this would make a real difference is also moving so fast the player could only hit it by dumb luck, so throwing off their timing by 16ms hopefully won't negatively impact gameplay.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php


I have been trying to wrap my mind around incorporating a fixed time step (dewitters game loop) into my game for almost three months now, but I just can't seem to conceptualize it in my mind for my game. I've read posts upon posts, articles upon articles, but still have a lot of questions.

So in short most of the articles say (and my understanding is), you separate the "updates" from the "render" and then use the difference in time and pass to the render to interpolate.

Others have mentioned it and I'm sure you've read it already, but this article is what helped me to fully understand this concept: http://gafferongames.com/game-physics/fix-your-timestep/.

To quote from the article, this sentence specifically describes conceptually what needs to happen:


"The renderer produces time and the simulation consumes it in discrete dt sized chunks."

What does this mean? It means that in your game loop, the first thing you do is check the time (t0), render a frame, and check the time again (t1). Assume for example that time elapsed between t0 and t1 (t1 - t0) is 34 milliseconds. Assume also that your "fixed timestep" for your physics/updates is 10 milliseconds (dt). The "render" stage produces 34ms, and the the "update" stage consumes the time in "discrete dt sized chunks"--that is, 10 ms chunks. That means that for this frame, you will run your update procedure 3 times, stepping forward by 10ms each time. Then you're going to have some time leftover: 4 ms. It is with this remaining value that you interpolate on your next render call.

When they say render are they speaking the actual process of drawing on the screen or the setting of values in the render (sprite x/y)?

Yes. When drawing, you interpolate position based on how far you are "between frames". In this case, you're about halfway between. I imagine this would not only to sprite position, but also to animation states, assuming those movements are also time-based.

To summarize, you basically end up with an update system which lags 1 frame behind the rendering. This may seem "wrong" somehow, but it works.

I can't help much with the networking portion of things (I've never programmed networked games), but I think using a queue somehow is the right approach.

If it helps, here's a real working example of such a loop that I wrote in Java: https://github.com/larsbutler/gamedemo/blob/master/src/com/larsbutler/gamedemo/core/Kernel.java#L68-L104

It's been a few years since I wrote that and some of the code is there is pretty odd, but that particular game loop is pretty solid, IMO.

Hope that helps.

This topic is closed to new replies.

Advertisement