跳转至内容

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
end
lua
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
end
lua
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
end
lua
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
end
lua
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
end
lua
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

指数平滑

smooth=αnew+(1α)old

真实帧率一直是稳定的 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
...