Game loop updating – and physics.
I’ve been on an epic quest to figure out how to best structure my game loop. The game loop is the one place where all your game’s logic should be updated. It’s the control center.
I’ve used delta time before, and that works fine in many cases. It’s where you measure the time since last game tick (aka frame) and tell all your objects how much time has passed so they can scale their responses accordingly. This is simple, and it works for very simple physics models. The trouble starts when you’re using a complex physics simulation to control objects.
I’m using Box2d, and for a physics sim, you want every update to use the same delta time. Fluctuations can cause the simulation to get all wigged out and blow up. Lucky for me, on the game I’m working on (not announced yet), I’m mostly only using Box2d for collision detection. There are no stacks of boxes or whatever, so there’s not a lot of simulating happening, and that makes it more tolerant to variable tick durations. Still not ideal, because it can cause weird collision glitches, like tunneling.
My view camera, though, tends to be very sensitive to update time fluctuations, and if the player moves more one frame than in the last, he jitters. It’s very annoying, and makes the whole game look jerky and twitchy, even at respectable framerates.
So my quest has been to find a game loop that can smooth all this out.
One thing I did was enforce a constant framerate. This allows the rendering to happen at a steady rate (like 30 fps) by sleeping for a few milliseconds if it’s rendering faster than your desired framerate. You basically measure if the last frame took more or less time than what you want, add (sleep your timer) or subtract (don’t sleep) that time from the current frame, and that evens them out.
So I had the physics decoupled from the rendering, but even with the steady framerate, the physics was updating at varying speeds to keep a steady 60 updates per second. So, for each frame (at 30 fps) the physics would typically update twice. But sometimes the interval since the last update would be more than that, so it would update 3 times, or maybe only once. Again, this causes jittery movement and makes the game feel really terrible.
So I’ve decided to just frame lock the physics and rendering. That means when there’s a frame rendered, there’s a corresponding physics update. As long as you have the CPU to stay at or above the minimum frames per second, the game will look nice and smooth.
This is great. Mostly. The problem happens when the computer can’t keep up with your desired framerate. Since things are on a fixed time step, the whole game slows down. Slow motion is only fun if you mean for it to happen! But I haven’t found a better solution, and I’m on a tight deadline. This’ll have to do for now.
Some linky goodness:
http://www.8bitrocket.com/newsdisplay.aspx?newspage=10248
http://gafferongames.wordpress.com/game-physics/fix-your-timestep/
December 1st, 2008 at 10:15 pm
It sounds like an awful amount of head-scratches to me. Thanks for the “linky goodness.” It was an informative read on what you have been going through.
December 1st, 2008 at 11:27 pm
It was a harrowing couple of days until I decided I was beyond a point of diminishing returns and just did the frame locking. I will be coming back to this problem later, though. Maybe not for this game, but definitely in other ones since they’ll all use this same game engine.
Thanks for reading!
December 1st, 2008 at 11:51 pm
What about Glen’s [gafferongames] interpolation approach?
December 2nd, 2008 at 10:26 am
I actually implemented his interpolation solution, but it didn’t solve the issue for me. It’s very possible that I just did it wrong.
But also I think we’re talking about jumps that are too big for 1 frame of interpolation to cover up. The motion can jump 5 or 6 pixels in some frames, so it still ends up jittery.
I don’t know if it’s the browser or what, but Flash can’t keep a steady framerate to save it’s butt. The tick times are all over the place, like 16ms, 27ms, 53ms, 34ms, 18ms, 60ms, etc. I graphed it out in debug output to help me visualize while diagnosing the problem(s) and the line was like vicious monster fangs, very jagged.
So, after wasting too much time spinning my wheels, I just framelocked and I’m moving on until I get more time later.
April 11th, 2009 at 7:58 pm
Heya, stumbled across your post while googling as I’m writing my first tile engine in as3 at the moment. I was playing with scrolling and wanted to make sure I was getting a smooth effect; I’ve ended up with this:
http://tinyrobot.co.uk/experiments/tiledscroller/
which I’m happy with so far, although in IE I had a pause every couple of seconds… I had a look at box2dflash’s source and noticed that they listened to the ENTER_FRAME event and simply blocked in the FRateLimiter class, I copied this method and it seems to smooth out IE a bit while unfortunately destabilizing the ‘physics’ of my little test. So personally I think I’m going to stick with the gaffer, since Firefox and standalone players work fine for me; I’d also like to note that I ported the same demo to pulpcore (http://www.interactivepulp.com/pulpcore/), with very smooth results across both browsers… so if you want to check out the sauce, give me a shout! Demo is here: http://tinyrobot.co.uk/experiments/pulptiledscroller/
Having said all that, locking updates and renders to, say, 30fps still looks ok to me; it’s only in situations like your own (with fast moving objects, for example) that I think there’s a general problem – so far my best looking solution is pulpcore, with framerate set to 100 and a fixed timestep of 10ms or below. Sorry to ramble on, I’ve been having similar irritations to yours for a couple of days now
April 12th, 2009 at 9:57 am
Hey tavis, thanks for posting your work. Your demo is very smooth here (FireFox 3), so you’re doing something right!
The main problem with physics and variable frame rates is, of course, that you might get collision tunneling. I was seeing some of that even just when walking around (popping through walls in certain cases).
Flash has really inconsistent timing because it defers its CPU usage to the system so that Flash won’t choke things up. Imagine a web page with 4 or 6 Flash ads running, each hogging the CPU. Good for Flash ad behavior, but not good for games. And not likely to change, so we’ll have to work with it.
Good luck with your games!