Page 1 of 1
Controlling FPS within the Love2D framework
Posted: Sun Nov 24, 2013 11:20 am
by lost_RD
Hi all, first post here, signed up to share this. I came up with a way to control FPS because I couldn't find any examples of other people doing it and it seemed like the kind of thing somebody might derive some benefit from.
The most important discovery was that of
love.run, without which this would not be possible. I defined the default code and proceeded to modify it. I also defined love.fps=42 in conf.lua.
love.draw
First I tried only calling love.draw after 1/desired_fps seconds which did work however FRAPS reported that the framerate was actually the update rate (650ish rather than the 42 I was using to test). love.timer.getFPS was also reporting the update rate so I then moved onto...
love.update
This modification was much simpler. Change
Code: Select all
if love.timer then love.timer.sleep(0.001) end
to
Code: Select all
if love.timer then love.timer.sleep(1/love.fps) end
and there you have it. Feel free to unpack the love files and take a peek.
If you wish to retain the smaller update increments you may not want to use the update method but I'm not sure if the draw method provides any real benefit since the framework appears to be drawing each update anyway.
[]
Posted: Sun Nov 24, 2013 6:35 pm
by bekey
-snip-
Re: Controlling FPS within the Love2D framework
Posted: Mon Nov 25, 2013 3:44 am
by lost_RD
I'm finding that the wiki is a bit sparse. With the amount of content on the forums, the wiki could easily be many times larger. In any case, I'm going to create my first game from scratch to completion first and then look through my code for things worth adding to the wiki.
Re: Controlling FPS within the Love2D framework
Posted: Wed Nov 27, 2013 2:16 pm
by T-Bone
I think the main reason it's not mentioned on the wiki is that there are very few situations where you'd need it. And if you do need it, you probably know what you're doing since you're trying to make something seriously complicated.
I think some beginners have a bit of "when all you have is a hammer, everything starts to look like a nail"-syndrome, if they've used game engines in the past that only work with constant framerates.
Once you've mastered dt, you will rarely ever (as in likely never) need a constant framerate.
Also, do you know about vsync? With it on, you get the same framerate as the monitor's refresh rate. Many serious games use that. But make sure to still use dt in case the user's monitor isn't set to the same frequency as yours.
Re: Controlling FPS within the Love2D framework
Posted: Sun Dec 22, 2013 5:36 am
by sclark39
There's actually a better way to do this defined in
http://love2d.org/wiki/love.timer.sleep
Copying here in case the wiki changes:
Code: Select all
function love.load()
min_dt = 1/30
next_time = love.timer.getMicroTime()
end
function love.update(dt)
next_time = next_time + min_dt
--rest of function here
end
function love.draw()
--rest of function here
local cur_time = love.timer.getMicroTime()
if next_time <= cur_time then
next_time = cur_time
return
end
love_timer_sleep(next_time - cur_time)
end
Re: Controlling FPS within the Love2D framework
Posted: Tue Dec 24, 2013 6:44 am
by Dattorz
Simply sleep()ing for the amount of ms of your target FPS will actually make your FPS lower than the target, especially if your game is doing heavy work.
If you are targeting 60 FPS, that makes 16.667 ms between frames. Let's say that your game takes a combined total of 5 ms to process logic and draw graphics. If you were to simply sleep exactly 16.667 ms and then process a frame, you would be doing 16.667 + 5 = 21.667 ms per frame = 46.15 FPS. Not the effect you want.
What you really want to be doing is sleep()ing for the remainder of time - ideally if your game takes 5 ms to process a frame, you would sleep for 11.667 frames. To this end you would use a variable to keep track of the time when the frame started by calling love.timer.getTime(), and while the current time - frame start time is less than 16.667 ms, you will simply do love.timer.sleep(.0001).
Keep in mind that with just about any multitasking operating system you won't get much resolution out of the system timer, so your program might oversleep by a millisecond or two. If you want more smoothness, just use a busy wait loop (remove the call to love.timer.sleep() and just keep the time comparison as an empty while loop. This will eat your CPU though, so it's not laptop-friendly. Another thing to keep in mind is that on some systems, performing a vsync will make the CPU sleep while waiting for the vertical blank, so you might also want to consider vsync use in conjunction with your main loop.
Re: Controlling FPS within the Love2D framework
Posted: Tue Dec 24, 2013 8:12 am
by Wojak
After some experimenting I think this is the best way to cap a frame rate without toasting the CPU:
(the FPS may go few frames above the limit though...)
Code: Select all
local FPS_L = 300
return {
run = function()
if love.math then
love.math.setRandomSeed(os.time())
end
if love.event then
love.event.pump()
end
if love.load then love.load(arg) end
-- We don't want the first frame's dt to include time taken by love.load.
if love.timer then love.timer.step() end
local dt = 0
-- Main loop time.
while true do
local m1 = love.timer.getTime( ) -- measure the time at the beginning of the main iteration
-- Process events.
if love.event then
love.event.pump()
for e,a,b,c,d in love.event.poll() do
if e == "quit" then
if not love.quit or not love.quit() then
if love.audio then
love.audio.stop()
end
return
end
end
love.handlers[e](a,b,c,d)
end
end
-- Update dt, as we'll be passing it to update
if love.timer then
love.timer.step()
dt = love.timer.getDelta()
end
-- Call update and draw
if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
if love.window and love.graphics and love.window.isCreated() then
love.graphics.clear()
love.graphics.origin()
if love.draw then love.draw() end
love.graphics.present()
end
local delta1 = love.timer.getTime() - m1 -- measure the time at the end of the main iteration and calculate delta
if love.timer then love.timer.sleep(1/FPS_L-delta1) end
end
end,
set = function(newlimit)
FPS_L = newlimit
end
}
You use it like this:
Code: Select all
--beginning of the main.lua file
function love.run() --delete default love.run
end
local frame_limiter =require("frame_limiter") –add the lib
--somewhere in the code
frame_limiter.set(fps_limit) -- set the cap
--end of the main.lua file
frame_limiter.run() -- start the main loop
Re: Controlling FPS within the Love2D framework
Posted: Tue Dec 24, 2013 8:43 am
by ivan
Dattorz wrote:If you are targeting 60 FPS, that makes 16.667 ms between frames. Let's say that your game takes a combined total of 5 ms to process logic and draw graphics.
It is important to reiterate, for Love2D noobs:
If during any frame Love2D takes a bit longer to draw (or your code takes longer to execute) the FPS will no longer be constant,
so
generally there is no way to ensure a constant frame rate - that's why you have to take dt into account.
Re: Controlling FPS within the Love2D framework
Posted: Mon Dec 30, 2013 6:19 am
by Dattorz
Actually, there is, as long as you keep a running track of how much time has been spent. Keep adding dt to your running count on time until it is larger than that of your target framerate, then keep processing frames (up to some max limit), and for each processed frame subtract from the running count until it's below target framerate again. I've used this method myself and it works just fine for regulating framerate.