I would like to point out that Anjo's code does not work reliably. Here is a corner case that shows how badly it can go wrong; it is demonstrated by the first code block below. Granted, the FPSCAP of five is unrealistic, but it gives you enough time to see the lengths of frames on screen in real time. It also shows that despite the cap, the program can run at up to 10 FPS (which is exactly what happens on this computer I am on). This is not what I ask the program to do when I put the 5 in there.
You can also try running this with a higher FPSCAP. Turn off vsync and log the times it takes to run each frame, and you'll probably see a pattern where occasional very short frames appear between the frames of expected length. This is because going over the limit for one frame lets the program logic run the next frame as fast as possible. I get a result of about 102 FPS when I ask for 60 and set vsync off in
conf.lua!
It would be better to have a solution that resulted in approximately equal length frames in any case, both under high load and low load from other processing in the game. And it should not depend on vsync, which can't be guaranteed to be usable on every computer your game might run on. I'm afraid this is not it:
Code: Select all
FPSCAP = 5 -- change if you want higher/lower max fps
local lastframe = nil
local diffs = {}
local LINES = 25
function love.update(dt)
local s = 1/FPSCAP - dt
if s > 0 then love.timer.sleep(s*1000) end
if lastframe then
local now = love.timer.getMicroTime()
table.insert(diffs, now - lastframe)
end
lastframe = love.timer.getMicroTime()
if #diffs > LINES then table.remove(diffs, 1) end
end
function love.draw()
love.graphics.print('FPS: ' .. love.timer.getFPS(), 20, 20)
for i = 1, #diffs do
love.graphics.print(tostring(diffs[i]), 20, 20+i*20)
end
end
This one has better behavior in this corner case. However, does it work so well with higher FPS and no vsync, and higher loads from other game logic? The timer granularity on some systems can also be an issue.
You be the judge! But remember that a good solution should be demonstrably a good solution--and in all cases you might encounter.
Code: Select all
FPSCAP = 5 -- change if you want higher/lower max fps
local lastframe = nil
local diffs = {}
local LINES = 25
function love.load()
lastframe = love.timer.getMicroTime()
end
function love.update(dt)
local slack = 1/FPSCAP - (love.timer.getMicroTime() - lastframe)
if slack > 0 then love.timer.sleep(1000*slack) end
local now = love.timer.getMicroTime()
local diff = now - lastframe
lastframe = now
table.insert(diffs, diff)
if #diffs > LINES then table.remove(diffs, 1) end
end
function love.draw()
love.graphics.print('FPS: ' .. love.timer.getFPS(), 20, 20)
for i = 1, #diffs do
love.graphics.print(tostring(diffs[i]), 20, 20+i*20)
end
end
Again, note that FPSCAP = 5 comes from wanting to read the output in real time!
In a real program, you should start keeping track of
lastframe when the game actually begins, of course. It does you no good to know the first one lasted 30 seconds or whatever it takes for the game to load completely