Skip to main content

How to check the actual frame rate (FPS) with Corona SDK

EDIT: This example has a follow-up in this blog post containing improved and object-oriented source code for the frame rate calculator.

In Corona SDK you set the target frame rate in config.lua to either 30 or 60 FPS (Frames Per Second). Then during application execution you can get this value through display.fps. However, remember that this is only the target frame rate, and the actual frame rate is something completely different. The actual FPS will fluctuate during program execution and can be significantly lower than the target FPS in case your app has too much to handle at any given moment.

I couldn't find any built-in way to get the actual FPS, so I decided to roll my own very simple solution to handle this. My frame rate calculator is just a Lua function that sets up an enter frame listener which then counts frames and calculates FPS based on time passed between the frames. The function startFrameRateCalculator accepts a single argument which is a callback function with a single parameter: the actual FPS.

Below is the source code for a little demo of this that spawns lots of colorful rectangles, moving from the center of the display towards the edges. The FPS value is displayed in a label, and the label is updated in the callback function injected to the startFrameRateCalculator function. If you run the program it should look something like this:

Actual FPS calculation demo
This was just a quick hack to test the idea, so feel free to improve the source code anyway you want. 
display.setStatusBar(display.HiddenStatusBar)
local function startFrameRateCalculator(callbackFunction)
local lastTimestampMs
local frameCounter = 0
Runtime:addEventListener("enterFrame", function()
frameCounter = frameCounter + 1
local currentTimestampMs = system.getTimer()
if (not lastTimestampMs) then
lastTimestampMs = currentTimestampMs
end
-- Calculate actual fps approximately four times every second
if (frameCounter >= (display.fps / 4)) then
local deltaMs = currentTimestampMs - lastTimestampMs
local fps = frameCounter / (deltaMs / 1000)
frameCounter = 0
lastTimestampMs = currentTimestampMs
callbackFunction(fps)
end
end)
end
local function createSquares(numberOfSquares)
local sizePixels = 2
local squares = {}
for i = 1, numberOfSquares do
local square = display.newRect(display.contentCenterX, display.contentCenterY, sizePixels, sizePixels)
local random = math.random
square:setFillColor(random(), random(), random())
square:toBack()
squares[#squares + 1] = square
end
return squares
end
------------------------------------------------------------------
math.randomseed( os.time() )
-- Setup a label to display the FPS value
local fpsLabel = display.newText({
x = display.contentCenterX,
y = 20,
fontSize = 72,
font = native.systemFontBold,
text = "FPS: " .. math.round(display.fps)
})
fpsLabel:setFillColor(1,1,0)
-- Start calculating FPS, and provide a callback function to update the label with current FPS value
startFrameRateCalculator(function(fps)
fpsLabel.text = "FPS: " .. math.round(fps)
end)
-- A simple way to be able to randomize where the squares should move
local moveTo = {
{
x = function() return math.random(0, display.contentWidth) end,
y = function() return 0 end,
},
{
x = function() return display.contentWidth end,
y = function() return math.random(0, display.contentHeight) end,
},
{
x = function() return math.random(0, display.contentWidth) end,
y = function() return display.contentHeight end,
},
{
x = function() return 0 end,
y = function() return math.random(0, display.contentHeight) end,
}
}
-- Endlessly create new squares in the center of the display, and send them off towards the edges of the display
timer.performWithDelay(10, function()
local numberOfSquares = 40
local squares = createSquares(numberOfSquares)
for i = 1, #squares do
local moveToFunctions = moveTo[math.random(1, #moveTo)]
local square = squares[i]
square.alpha = 0
transition.to(square, {
x = moveToFunctions.x(),
y = moveToFunctions.y(),
rotation = math.random(-360, 360),
time = 500,
xScale = 20,
yScale = 20,
alpha = 1,
onComplete = function()
display.remove(square)
end
})
end
end, 0)
view raw main.lua hosted with ❤ by GitHub

Comments