A couple of weeks back I wrote this post about how to calculate the actual frame rate of your game rather than just hoping that the target frame rate found in display.fps will be met. Back then I only used it as en experiment, but today I wanted to implement it in my game Ice Trap to be able to reduce or disable some animations on slower running devices. I ended up rewriting the frame rate calculator in an object-oriented fashion to make it cleaner and more reusable.
It should be very easy to use. Just create a new instance of the FPSCalculator, passing in a callback function and some optional configuration parameters. In the callback function you'll have access to the current FPS as well as the FPS ratio, i.e (actual_FPS/target_FPS). If none of the optional config parameters are specified the callback will be invoked once every second, regardless of whether there's been a FPS drop or not.
Check out the whole source code below, including some example usage code, and make modifications and extensions to it as you see fit.
It should be very easy to use. Just create a new instance of the FPSCalculator, passing in a callback function and some optional configuration parameters. In the callback function you'll have access to the current FPS as well as the FPS ratio, i.e (actual_FPS/target_FPS). If none of the optional config parameters are specified the callback will be invoked once every second, regardless of whether there's been a FPS drop or not.
Check out the whole source code below, including some example usage code, and make modifications and extensions to it as you see fit.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
This is a simple example showing how to use the FPSCalculator class | |
Markus Ranner 2016 | |
--]] | |
local FPSCalculator = require("FPSCalculator") | |
local fpsCalculator = FPSCalculator.new( | |
function(fps, fpsRatio) | |
print("fps = " .. fps .. ", ratio = " .. fpsRatio) | |
-- Do things here to handle a drop in frame rate, such as disable animations | |
end, | |
{ | |
fpsRatioWarningThreshold = 0.95, | |
timeBetweenCalculationsMs = 10000, | |
} | |
) | |
fpsCalculator:start() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
Frame rate calculator class, used to find out the actual frame rate of a game and react to drops in FPS. | |
Markus Ranner 2016 | |
--]] | |
local FPSCalculator = {} | |
FPSCalculator.__index = FPSCalculator | |
--- Private functions -------------- | |
function FPSCalculator:calculateFPS() | |
self.frameCounter = self.frameCounter + 1 | |
local currentTimestampMs = system.getTimer() | |
if (not self.lastCalculationTimestampMs) then | |
self.lastCalculationTimestampMs = currentTimestampMs | |
end | |
local deltaTimeMs = currentTimestampMs - self.lastCalculationTimestampMs | |
-- Calculate average fps for the specified time period | |
if ( deltaTimeMs >= self.timeBetweenCalculationsMs ) then | |
local fps = self.frameCounter / (deltaTimeMs / 1000) | |
self.frameCounter = 0 | |
self.lastCalculationTimestampMs = currentTimestampMs | |
local fpsRatio = fps/display.fps | |
if ((not self.fpsRatioWarningThreshold) or (fpsRatio <= self.fpsRatioWarningThreshold)) then | |
self.callback(fps, fpsRatio) | |
end | |
end | |
end | |
--- Public functions -------------- | |
function FPSCalculator:start() | |
if (self.isStarted) then | |
return | |
end | |
-- Reset some state | |
self.isStarted = true | |
self.frameCounter = 0 | |
self.lastCalculationTimestampMs = nil | |
-- Setup the calculation function | |
self.calculationFunction = function() self:calculateFPS() end | |
Runtime:addEventListener("enterFrame", self.calculationFunction) | |
end | |
function FPSCalculator:stop() | |
self.isStarted = false, | |
Runtime:removeEventListener("enterFrame", self.calculationFunction) | |
end | |
--[[ | |
callback(fps, fpsRatio) - Required. A callback function with params: | |
fps - The average frame rate during the last calculation period | |
fpsRatio - The ratio between actual fps and target fps (fps/display.fps) | |
params - Optional table of configuration params. The following params are allowed and are optional. | |
timeBetweenCalculationsMs - How often to calculate fps. Default = 1000 ms. | |
fpsRatioWarningThreshold - A number between 0-1. If specified, the callback will only be called if fpsRatio drops below this threshold number. | |
--]] | |
function FPSCalculator.new(callback, params) | |
params = params or {} | |
local newCalculator = { | |
isStarted = false, | |
frameCounter = 0, | |
lastCalculationTimestampMs = nil, | |
calculationFunction = nil, -- Will be set when start() is called | |
callback = callback, | |
timeBetweenCalculationsMs = params.timeBetweenCalculationsMs or 1000, | |
fpsRatioWarningThreshold = params.fpsRatioWarningThreshold, | |
} | |
setmetatable(newCalculator, FPSCalculator) | |
return newCalculator | |
end | |
return FPSCalculator |
Comments
Post a Comment