Skip to content

Instantly share code, notes, and snippets.

@jmiskovic
Created April 19, 2025 20:27
Show Gist options
  • Select an option

  • Save jmiskovic/820397f850ca5d48b70f43b6d2236cf4 to your computer and use it in GitHub Desktop.

Select an option

Save jmiskovic/820397f850ca5d48b70f43b6d2236cf4 to your computer and use it in GitHub Desktop.
Stabilize the LÖVR physics and state updates by running them at consistent intervals regardless of frame rate
-- require this file to have reduced input lag and game logic that runs consistently
-- inspired by https://gafferongames.com/post/fix_your_timestep/
-- note: this decouples update() from draw(); update() can run multiple times per frame
local m = {}
m.update_delta = 1 / 60
function lovr.run()
if lovr.timer then lovr.timer.step() end
if lovr.load then lovr.load(arg) end
local current_time = 0.0
local accumulator = 0.0
local t = 0.0
local previous_state = {}
local current_state = {}
return function()
local dt = m.update_delta
local window
if lovr.graphics then -- get window pass earlier than LÖVR default to reduce input lag
window = lovr.graphics.getWindowPass()
end
if lovr.system then lovr.system.pollEvents() end
if lovr.event then
for name, a, b, c, d in lovr.event.poll() do
if name == 'restart' then return 'restart', lovr.restart and lovr.restart()
elseif name == 'quit' and (not lovr.quit or not lovr.quit(a)) then return a or 0
elseif name ~= 'quit' and lovr.handlers[name] then lovr.handlers[name](a, b, c, d) end
end
end
if lovr.timer then lovr.timer.step() end
if lovr.headset and lovr.headset.isActive() then lovr.headset.update() end
local new_time = lovr.timer.getTime()
local frame_time = new_time - current_time
if frame_time > 0.25 then frame_time = 0.25 end
current_time = new_time
accumulator = accumulator + frame_time
while accumulator >= dt do
previous_state = current_state
if lovr.update then lovr.update(dt, t) end
t = t + dt
accumulator = accumulator - dt
end
local alpha = accumulator / dt
local state = {}
for k, v in pairs(current_state) do
state[k] = v * alpha + previous_state[k] * (1.0 - alpha)
end
if lovr.graphics then
local headset = lovr.headset and lovr.headset.getPass()
if headset and (not lovr.draw or lovr.draw(headset, state)) then headset = nil end
if window and (not lovr.mirror or lovr.mirror(window, state)) then window = nil end
lovr.graphics.submit(headset, window)
lovr.graphics.present()
end
if lovr.headset then lovr.headset.submit() end
if lovr.math then lovr.math.drain() end
end
end
return m
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment