I'm currently developing this rhythm game in lua (on top of a c++ engine) and I'm having trouble keeping a steady playhead position for the song currently playing.

The playhead position that the engine gives me updates in steps, so I get a fresh one every 2, 3 or 4 frames. But I need to have a steady one for sprites moving smoothly with the rhythm and stuff.

So I just keep track of my own playhead variable, which I initialize in 0 and then constantly add delta time to it. This variable eventually gets out of sync with the actual playhead, so every time I get a fresh playhead (or a "new step"), I correct my variable using the average between these two.

This however results in choppy movement.

I've seen many easing functions out there but I'm not sure which one would work in this case, nor when should I call it.

What would be the best way to ease my playhead variable into the stepped one?

This is the code I excecute every frame:

-- add delta to my own playhead variable

playhead = playhead + delta_time

-- if there's a new stepped_playhead value, correct my playhead

if stepped_playhead ~= last_stepped_playhead then
    playhead = (playhead + stepped_playhead) / 2
    last_stepped_playhead = stepped_playhead

1 Answer 1


In your code, the choppiness is coming from the fact that you are jumping every time there is a syncing frame. Jumping to the halfway point is a good idea, but if the displayed playhead is consistently moving away from the actual playhead (or vice versa), then it will constantly be jumping back slightly (or, alternatively, forward).

One way to smooth this out would be to adjust the speed of your displayed playhead at sync frames instead of adjusting the actual position:

frames_since_sync = frames_since_sync + 1

if stepped_playhead ~= last_stepped_playhead then
    sync_delta = (stepped_playhead - playhead) / frames_since_sync

    last_stepped_playhead = stepped_playhead
    frames_since_sync = 0

playhead = playhead + delta_time + sync_delta

The lines sync_delta = (stepped_playhead - playhead) / frames_since_sync and playhead = playhead + delta_time + sync_delta are main changes here.

Essentially, what we're doing is using the number of frames since the last sync frame as an estimate for the number of frames until the next sync frame. Then we divide the error between our two playheads by that number of frames. This new sync_delta is used to speed up or slow down the displayed playhead so that it should approach the correct position by the time the next sync frame comes around. At the next sync frame, the process is repeated, and the speed adjusted again to try and keep the two playheads near each other.

  • \$\begingroup\$ thanks for the answer, I don't need it anymore but <3 ! \$\endgroup\$
    – burzum
    Commented Nov 16, 2019 at 2:48
  • \$\begingroup\$ I figured as much, but I thought it might be helpful to pose a solution in case it might help others. Thanks for the check mark! \$\endgroup\$
    – pladams9
    Commented Nov 18, 2019 at 18:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .