Controlling FPS within the Love2D framework

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
User avatar
lost_RD
Prole
Posts: 23
Joined: Sun Nov 24, 2013 9:16 am
Location: Australia

Controlling FPS within the Love2D framework

Post 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
fps_draw_method.love
FPS control by choosing when to draw
(1.76 KiB) Downloaded 443 times
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
fps_update_method.love
FPS control by choosing when to update
(1.75 KiB) Downloaded 475 times
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.
bekey
Party member
Posts: 255
Joined: Tue Sep 03, 2013 6:27 pm

[]

Post by bekey »

-snip-
Last edited by bekey on Fri Jan 24, 2014 2:02 am, edited 1 time in total.
User avatar
lost_RD
Prole
Posts: 23
Joined: Sun Nov 24, 2013 9:16 am
Location: Australia

Re: Controlling FPS within the Love2D framework

Post 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.
User avatar
T-Bone
Inner party member
Posts: 1492
Joined: Thu Jun 09, 2011 9:03 am

Re: Controlling FPS within the Love2D framework

Post 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.
sclark39
Prole
Posts: 5
Joined: Wed Jan 02, 2013 4:36 pm

Re: Controlling FPS within the Love2D framework

Post 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
User avatar
Dattorz
Citizen
Posts: 66
Joined: Sat Oct 27, 2012 12:32 am
Contact:

Re: Controlling FPS within the Love2D framework

Post 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.
Wojak
Party member
Posts: 134
Joined: Tue Jan 24, 2012 7:15 pm

Re: Controlling FPS within the Love2D framework

Post 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  
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Controlling FPS within the Love2D framework

Post 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.
User avatar
Dattorz
Citizen
Posts: 66
Joined: Sat Oct 27, 2012 12:32 am
Contact:

Re: Controlling FPS within the Love2D framework

Post 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.
Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests