15. 翻译,dt,FPS
3.11,翻译了 arkanoid 教程,做一下昨天剩的题。
delta time
lua
function love.run()
if love.math then love.math.setRandomSeed(os.time()) end
if love.load then love.load(arg) end
if love.timer then love.timer.step() end
local dt = 0
while true do
if love.event then
love.event.pump()
for name, a,b,c,d,e,f in love.event.poll() do
if name == "quit" then
if not love.quit or not love.quit() then
return a
end
end
love.handlers[name](a,b,c,d,e,f)
end
end
-- 真实耗时多少就传多少
if love.timer then
love.timer.step()
dt = love.timer.getDelta()
end
if love.update then love.update(dt) end
if love.graphics and love.graphics.isActive() then
love.graphics.clear(love.graphics.getBackgroundColor())
love.graphics.origin()
if love.draw then love.draw() end
love.graphics.present()
end
if love.timer then love.timer.sleep(0.001) end
end
endlua
function love.run()
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
if love.timer then love.timer.step() end
local dt = 0
return function()
if love.event then
love.event.pump()
for name, a,b,c,d,e,f in love.event.poll() do
if name == "quit" then
if not love.quit or not love.quit() then
return a or 0
end
end
love.handlers[name](a,b,c,d,e,f)
end
end
-- dt 可变,物理容易不稳定
if love.timer then dt = love.timer.step() end
if love.update then love.update(dt) end
if love.graphics and love.graphics.isActive() then
love.graphics.origin()
love.graphics.clear(love.graphics.getBackgroundColor())
if love.draw then love.draw() end
love.graphics.present()
end
if love.timer then love.timer.sleep(0.001) end
end
endlua
function love.run()
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
if love.timer then love.timer.step() end
local dt = 1/60
return function()
if love.event then
love.event.pump()
for name, a,b,c,d,e,f in love.event.poll() do
if name == "quit" then
if not love.quit or not love.quit() then
return a or 0
end
end
love.handlers[name](a,b,c,d,e,f)
end
end
-- 不管真实耗时多少,每帧都传 1/60
if love.update then love.update(dt) end
if love.graphics and love.graphics.isActive() then
love.graphics.origin()
love.graphics.clear(love.graphics.getBackgroundColor())
if love.draw then love.draw() end
love.graphics.present()
end
if love.timer then love.timer.sleep(0.001) end
end
endlua
function love.run()
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
if love.timer then love.timer.step() end
local dt = 0
local upper_dt = 1/60
return function()
if love.event then
love.event.pump()
for name, a,b,c,d,e,f in love.event.poll() do
if name == "quit" then
if not love.quit or not love.quit() then
return a or 0
end
end
love.handlers[name](a,b,c,d,e,f)
end
end
if love.timer then dt = love.timer.step() end
-- 真实耗时大的就切片处理,单次传入的 dt 过大会进入死亡循环
while dt > 0 do
local current_dt = math.min(dt, upper_dt)
if love.update then love.update(current_dt) end
dt = dt - current_dt
end
if love.graphics and love.graphics.isActive() then
love.graphics.origin()
love.graphics.clear(love.graphics.getBackgroundColor())
if love.draw then love.draw() end
love.graphics.present()
end
if love.timer then love.timer.sleep(0.001) end
end
endlua
function love.run()
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
if love.timer then love.timer.step() end
local dt = 0
local fixed_dt = 1/60
local accumulator = 0
return function()
if love.event then
love.event.pump()
for name, a,b,c,d,e,f in love.event.poll() do
if name == "quit" then
if not love.quit or not love.quit() then
return a or 0
end
end
love.handlers[name](a,b,c,d,e,f)
end
end
if love.timer then dt = love.timer.step() end
accumulator = accumulator + dt
-- 累计一个固定步长再跑一次物理更新
while accumulator >= fixed_dt do
if love.update then love.update(fixed_dt) end
accumulator = accumulator - fixed_dt
end
if love.graphics and love.graphics.isActive() then
love.graphics.origin()
love.graphics.clear(love.graphics.getBackgroundColor())
if love.draw then love.draw() end
love.graphics.present()
end
if love.timer then love.timer.sleep(0.001) end
end
endlua
function love.run()
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
if love.timer then love.timer.step() end
local dt = 0
local dt_smooth = 1 / 100
local run_time = 0
return function()
run_time = love.timer.getTime()
if love.event and G and G.CONTROLLER then
love.event.pump()
local _n, _a, _b, _c, _d, _e, _f, touched
for name, a, b, c, d, e, f in love.event.poll() do
if name == "quit" then
if not love.quit or not love.quit() then
return a or 0
end
end
if name == 'touchpressed' then
touched = true
elseif name == 'mousepressed' then
_n, _a, _b, _c, _d, _e, _f = name, a, b, c, d, e, f
else
love.handlers[name](a, b, c, d, e, f)
end
end
if _n then
love.handlers['mousepressed'](_a, _b, _c, touched)
end
end
if love.timer then dt = love.timer.step() end
-- 给可变 dt 做一个指数平滑,并且给了一个 dt 上限 0.1
dt_smooth = math.min(0.8 * dt_smooth + 0.2 * dt, 0.1)
if love.update then love.update(dt_smooth) end
if love.graphics and love.graphics.isActive() then
if love.draw then love.draw() end
love.graphics.present()
end
-- 这一帧实际花了多少时间,上限为 0.1
run_time = math.min(love.timer.getTime() - run_time, 0.1)
-- 帧率上限 500 FPS
G.FPS_CAP = G.FPS_CAP or 500
-- 这一帧跑的太快就 sleep 一下补足时间
if run_time < 1/G.FPS_CAP then
love.timer.sleep(1/G.FPS_CAP - run_time)
end
end
end指数平滑
真实帧率一直是稳定的 100FPS 的话,dt 就是 0.01,某一帧突然卡顿 dt 跳到 0.1:
0.01 → 0.01
0.01 → 0.01
0.1 → 0.8*0.01 + 0.2*0.1 = 0.028
0.01 → 0.8*0.028 + 0.2*0.01 = 0.024
0.01 → 0.8*0.024 + 0.2*0.01 = 0.021
...