This module calculates the average gain of any stat or currency in your game, there aren’t a lot of resources out there about this, so I decided to create a simple and easy to use module.
CONSTRUCTOR
new(seconds: number, updateInterval: number, allowNegative: boolean, roundAverage: boolean)
new(seconds: number)
"update interval is 0 by default"
METHODS
getAverage(): number
"returns the average gain"
update(amount: number, callback)
"updates the average gain"
destroy() ONLY WHEN updateInterval > 0
"destroys the update loop"
How can this be useful? Let’s say you have a tycoon, and you want to show the player how much he is getting per second, this module for you!
--// Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
--// Modules
local AverageGain = require(ReplicatedStorage.AverageGain)
--// Variables
local label = script.Parent.TextLabel
local cash = 0
local cashAverage = AverageGain.new(1, .5) -- average per second, updates every .5 seconds
--[[
Ex:
AverageGain.new(60) -- average per minute, updates when update() is called
AverageGain.new(3600, 0) -- average per hour, updates when update() is called
...
]]
--// Functions
local function updateText(value, average)
label.Text = `Cash: {value} ({average}/s)`
end
--// Init
updateText(cash, cashAverage:getAverage())
task.spawn(function()
while true do
task.wait(.1)
cash += 1
cashAverage:update(cash, function(average) -- updates the average and updates the ui
updateText(cash, average)
end)
end
end)
That’s it, feel free to change and use it for your projects!
local averageGain = {}
averageGain.__index = averageGain
--// Private Functions
local function roundDecimals(num, numDecimalPlaces)
local mult = 10 ^ (numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
--// Public Functions
function averageGain.new(seconds: number, updateInterval: number, allowNegative: boolean, roundAverage: boolean)
local self = setmetatable({}, averageGain)
self.previous = nil
self.lastAverage = 0
self.average = 0
self._seconds = seconds
self._updateInterval = updateInterval or 0
self._allowNegative = allowNegative
self._roundAverage = roundAverage
self:_init()
return self
end
function averageGain:getAverage(): number
local average = (self._updateInterval > 0) and self.lastAverage or self.average
return self._roundAverage and math.floor(average) or average
end
function averageGain:update(amount: number, callback)
if not self.callback then self.callback = callback end
if not self.previous then self.previous = amount end
local difference = (amount - self.previous) * self._seconds
self.previous = amount
if not self._allowNegative and (self.previous <= 0 or difference <= 0) then
self.callback( self:getAverage() )
return
end
self.average = roundDecimals(self.average + difference, 2)
self.callback( self:getAverage() )
task.delay(1, function()
self.average = roundDecimals(self.average - difference, 2)
self.callback( self:getAverage() )
end)
end
function averageGain:_init()
if self._updateInterval <= 0 then return end
self._thread = task.spawn(function()
while true do
if not self.callback then task.wait() continue end
task.wait(self._updateInterval)
self.lastAverage = self.average
self.callback(self.lastAverage)
end
end)
end
function averageGain:destroy()
if self._thread and coroutine.status(self._thread) == "suspended" then
task.cancel(self._thread)
end
end
return averageGain