Page 1 of 4

Stuttering & Fixed Timesteps

Posted: Thu Sep 29, 2011 5:37 am
by Bryant
Hey everyone :) I'm new to LÖVE and Lua, and I've been messing around with the examples you've all posted online. The level of community support this framework has is refreshing :)

I created a simple project that features a box you can move around with the arrow keys. I'm noticing, however, that the box stutters on occasion. It's minor, and you probably wouldn't notice it if a lot was happening on the screen, but it's definitely there.

I thought this might be because the update and draw functions were falling out of sync. But that shouldn't be the case because love.run calls draw() immediately after update() every time, right?

I tried a few different approaches to my update loop which you can see commented out in the .love file. I tried a fixed timestep without dt, a fixed timestep with dt, and a variable timestep with dt. They all have stuttering problems :(

Next I tried turning off vsync, but that slowed everything down to a crawl (shouldn't it have sped everything up? I might not have tested it with the three update loop configurations...).

Is there any way around this? I know a lot of people link to this article about fixing your timestep. Maybe I'm missing the step about integrating or interpolating my moving object(s)?

The default LÖVE app with the spinning logo and scrolling starfield runs so smoothly! What am I doing differently? :?

Thank you all for the help :)

Re: Stuttering

Posted: Thu Sep 29, 2011 5:45 am
by T-Bone
The accumulator is wierd. Don't do it. The "variable timestep with dt" is better. Doesn't stutter at all for me.

draw() and update(dt) are run independently of each other. That's a good thing.

Re: Stuttering

Posted: Thu Sep 29, 2011 5:56 am
by Bryant
I agree that the accumulator is weird :) But what other option is there for games that require a high level of precision like a competitive fighting game or a rhythm game? In those cases a single frame makes all the difference, and a variable timestep won't suffice.

Re: Stuttering & Fixed Timesteps

Posted: Thu Sep 29, 2011 12:58 pm
by slime
Bryant wrote:Is there any way around this? I know a lot of people link to this article about fixing your timestep. Maybe I'm missing the step about integrating or interpolating my moving object(s)?

The default LÖVE app with the spinning logo and scrolling starfield runs so smoothly! What am I doing differently? :?

Thank you all for the help :)
Yeah, for a fixed update loop with a variable framerate (which is generally what you want), you'll need to rewrite the love.run function to have a love.update accumulator as well as a love.draw interpolator.
The default variable update and variable framerate loop shouldn't cause any problems usually though, as long as you multiply the appropriate things by the deltatime.

Re: Stuttering & Fixed Timesteps

Posted: Thu Sep 29, 2011 1:31 pm
by Taehl
I use an accumulator technique in my game Underlife, and it runs beautifully. Here's basically what I do:

Code: Select all

function love.update(dt)
	local accum = dt
	while accum > 0 do		-- accumulator for physics! no more penetration!
		local dt = math.min( 1/50, accum )	-- use whatever max dt value works best for you
		accum = accum - dt
		
		-- now, do whatever it is you need to do with dt
	end
end
I hope that helps you.

Re: Stuttering

Posted: Thu Sep 29, 2011 4:06 pm
by kikito
Bryant wrote:I agree that the accumulator is weird :) But what other option is there for games that require a high level of precision like a competitive fighting game or a rhythm game? In those cases a single frame makes all the difference, and a variable timestep won't suffice.
I might be wrong, but it seems to me that the variable timestep actually gives you more control over those cases. I don't see what problems a fixed frame rate would solve that can't be done better with a variable one.

Re: Stuttering

Posted: Thu Sep 29, 2011 4:30 pm
by slime
kikito wrote:
Bryant wrote:I agree that the accumulator is weird :) But what other option is there for games that require a high level of precision like a competitive fighting game or a rhythm game? In those cases a single frame makes all the difference, and a variable timestep won't suffice.
I might be wrong, but it seems to me that the variable timestep actually gives you more control over those cases. I don't see what problems a fixed frame rate would solve that can't be done better with a variable one.
I suggest you read http://gafferongames.com/game-physics/f ... -timestep/ (linked in the OP), it makes excellent points.
However, a fixed update timestep is usually only needed in multiplayer games with high precision physics where it's much better to be deterministic.

Re: Stuttering

Posted: Thu Sep 29, 2011 7:45 pm
by Xgoff
slime wrote:I suggest you read http://gafferongames.com/game-physics/f ... -timestep/ (linked in the OP), it makes excellent points.
However, a fixed update timestep is usually only needed in multiplayer games with high precision physics where it's much better to be deterministic.
or, in my game (assuming i ever work on it), a timing system. if i call wait() i want an object to wait *exactly* some number of ticks, not plus or minus some number of milliseconds. this also means floats are out, unless they're limited to being exactly representable

Re: Stuttering & Fixed Timesteps

Posted: Thu Sep 29, 2011 10:32 pm
by Bryant
Thanks for all the great responses!

slime -- A fixed update loop with a variable framerate is exactly what I'm looking for. I'll try rewriting love.run() with the accumulator method. But interpolating any "leftover" time in the draw() function is where I get confused (in the "Fix Your Timestep" article, this is where the author uses a "blending factor" to linearly interpolate the simulation before rendering).

Also, maybe I'm misunderstanding something, but is LÖVE's rendering really decoupled from the update loop? Just looking at the default implementation of love.run(), it looks like update() and draw() are called on the same timestep. So draw() will never be called more frequently than update(). If anything, with the accumulator method, draw() might be called *less* frequently. If that's true, jittering/stuttering seems unavoidable :(

Xgoff -- Floating point precision is exactly the problem I have with a variable timestep :( Have you tried implementing your own fixed timestep in LÖVE yet?

Thanks again, everyone. As a side note, here's a good article explaining XNA's approach to the problem.

EDIT: Two more good XNA articles explaining the problem and potential solutions: Part 1 and Part 2.

Re: Stuttering & Fixed Timesteps

Posted: Thu Sep 29, 2011 10:53 pm
by Taehl
Bryant wrote:slime -- A fixed update loop with a variable framerate is exactly what I'm looking for. I'll try rewriting love.run() with the accumulator method. But interpolating any "leftover" time in the draw() function is where I get confused (in the "Fix Your Timestep" article, this is where the author uses a "blending factor" to linearly interpolate the simulation before rendering).
The accumulator code I posted above is aimed at running updates more times than it draws. Or as the article you linked to phrased it, "Call Update extra times (without calling Draw) until we catch up.".
Bryant wrote:Also, maybe I'm misunderstanding something, but is LÖVE's rendering really decoupled from the update loop? Just looking at the default implementation of love.run(), it looks like update() and draw() are called on the same timestep. So draw() will never be called more frequently than update(). If anything, with the accumulator method, draw() might be called *less* frequently. If that's true, jittering/stuttering seems unavoidable :(
You're right - with Love2D's default love.run(), you get exactly one love.update() and then one love.draw(). And with my accumulator code, you'll get more updates than drawn frames.

If you want to draw frames faster than you're updating the game, you'll need some sort of bizarre code which predicts object movement and integrates the prediction with reality once an update rolls around. And you'll need to do all this faster than it takes to just update the world. But honestly, this strikes me as patently crazy.

Also, in your .love file, FIXED TIMESTEP WITH DT and VARIABLE TIMESTEP WITH DT both run smoothly for me, while FIXED TIMESTEP WITHOUT DT is slightly less smooth.