Created
January 19, 2021 17:49
-
-
Save a327ex/68fb459fbed211dd4c6627a0a5233ee0 to your computer and use it in GitHub Desktop.
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
-- The base Timer class. Useful for juicing things up generally. | |
-- A global instance of this called "timer" is available by default. | |
Timer = Object:extend() | |
function Timer:new() | |
self.timers = {} | |
end | |
-- Calls the action every frame until it's cancelled via timer:cancel. | |
-- The tag must be passed in otherwise there will be no way to stop this from running. | |
-- If after is passed in then it is called after the run is cancelled. | |
function Timer:run(action, after, tag) | |
local tag = tag or random:uid() | |
local after = after or function() end | |
self.timers[tag] = {type = "run", after = after, action = action} | |
end | |
-- Calls the action after delay seconds. | |
-- Or calls the action after the condition is true. | |
-- If tag is passed in then any other timer actions with the same tag are automatically cancelled. | |
-- timer:after(2, function() print(1) end) -> prints 1 after 2 seconds | |
-- timer:after(function() return self.should_print_1 end, function() print(1) end) -> prints 1 after self.should_print_1 is set to true | |
function Timer:after(delay, action, tag) | |
local tag = tag or random:uid() | |
if type(delay) == "number" or type(delay) == "table" then | |
self.timers[tag] = {type = "after", timer = 0, unresolved_delay = delay, delay = self:resolve_delay(delay), action = action} | |
else | |
self.timers[tag] = {type = "conditional_after", condition = delay, action = action} | |
end | |
end | |
-- Calls the action every delay seconds. | |
-- Or calls the action once every time the condition becomes true. | |
-- If times is passed in then it only calls action for that amount of times. | |
-- If after is passed in then it is called after the last time action is called. | |
-- If tag is passed in then any other timer actions with the same tag are automatically cancelled. | |
-- timer:every(2, function() print(1) end) -> prints 1 every 2 seconds | |
-- timer:every(2, function() print(1) end, 5, function() print(2) end) -> prints 1 every 2 seconds 5 times, and then prints 2 | |
function Timer:every(delay, action, times, after, tag) | |
local times = times or 0 | |
local after = after or function() end | |
local tag = tag or random:uid() | |
if type(delay) == "number" or type(delay) == "table" then | |
self.timers[tag] = {type = "every", timer = 0, unresolved_delay = delay, delay = self:resolve_delay(delay), action = action, times = times, max_times = times, after = after} | |
else | |
self.timers[tag] = {type = "conditional_every", condition = delay, last_condition = false, action = action, times = times, max_times = times, after = after} | |
end | |
end | |
-- Same as every except the action is called immediately when this function is called, and then every delay seconds. | |
function Timer:every_immediate(delay, action, times, after, tag) | |
local times = times or 0 | |
local after = after or function() end | |
local tag = tag or random:uid() | |
self.timers[tag] = {type = "every", timer = 0, unresolved_delay = delay, delay = self:resolve_delay(delay), action = action, times = times, max_times = times, after = after} | |
action() | |
end | |
-- Calls the action every frame for delay seconds. | |
-- Or calls the action every frame the condition is true. | |
-- If after is passed in then it is called after the duration ends or after the condition becomes false. | |
-- If tag is passed in then any other timer actions with the same tag are automatically cancelled. | |
-- timer:during(5, function() print(random:float(0, 100)) end) | |
-- timer:during(function() return self.should_print_random_float end, function() print(random:float(0, 100)) end) -> prints the random float as long as self.should_print_random_float is true | |
function Timer:during(delay, action, after, tag) | |
local after = after or function() end | |
local tag = tag or random:uid() | |
if type(delay) == "number" or type(delay) == "table" then | |
self.timers[tag] = {type = "during", timer = 0, unresolved_delay = delay, delay = self:resolve_delay(delay), action = action, after = after} | |
elseif type(delay) == "function" then | |
self.timers[tag] = {type = "conditional_during", condition = delay, last_condition = false, action = action, after = after} | |
end | |
end | |
-- Tweens the target's values specified by the source table for delay seconds using the given tweening method. | |
-- All tween methods can be found in the math/math file. | |
-- If after is passed in then it is called after the duration ends. | |
-- If tag is passed in then any other timer actions with the same tag are automatically cancelled. | |
-- timer:tween(0.2, self, {sx = 0, sy = 0}, math.linear) -> tweens this object's scale variables to 0 linearly over 0.2 seconds | |
-- timer:tween(0.2, self, {sx = 0, sy = 0}, math.linear, function() self.dead = true end) -> tweens this object's scale variables to 0 linearly over 0.2 seconds and then kills it | |
function Timer:tween(delay, target, source, method, after, tag) | |
local method = method or math.linear | |
local after = after or function() end | |
local tag = tag or random:uid() | |
local initial_values = {} | |
for k, _ in pairs(source) do initial_values[k] = target[k] end | |
self.timers[tag] = {type = "tween", timer = 0, unresolved_delay = delay, delay = self:resolve_delay(delay), target = target, initial_values = initial_values, source = source, method = method, after = after} | |
end | |
-- Cancels a timer action based on its tag. | |
-- This is automatically called if repeated tags are given to timer actions. | |
function Timer:cancel(tag) | |
if self.timers[tag].type == "run" then | |
self.timers[tag].after() | |
end | |
self.timers[tag] = nil | |
end | |
-- Returns the delay of a given tag. | |
-- This is useful when delays are set randomly (timer:every({2, 4}, ...) would set the delay at a random number between 2 and 4) and you need to know what the value chosen was. | |
function Timer:get_delay(tag) | |
return self.timers[tag].delay | |
end | |
-- Returns the current iteration of an every timer action with the given tag. | |
-- Useful if you need to know that its the nth time an every action has been called. | |
function Timer:get_every_iteration(tag) | |
return self.timers[tag].max_times - self.timers[tag].times | |
end | |
-- Returns the elapsed time of a given timer as a number between 0 and 1. | |
-- Useful if you need to know where you currently are in the duration of a during call. | |
function Timer:get_during_elapsed_time(tag) | |
return self.timers[tag].timer/self.timers[tag].delay | |
end | |
function Timer:resolve_delay(delay) | |
if type(delay) == "table" then | |
return random:float(delay[1], delay[2]) | |
else | |
return delay | |
end | |
end | |
function Timer:update(dt) | |
for tag, timer in pairs(self.timers) do | |
timer.timer = timer.timer + dt | |
if timer.type == "run" then | |
timer.action() | |
elseif timer.type == "after" then | |
if timer.timer > timer.delay then | |
timer.action() | |
self.timers[tag] = nil | |
end | |
elseif timer.type == "conditional_after" then | |
if timer.condition() then | |
timer.action() | |
self.timers[tag] = nil | |
end | |
elseif timer.type == "every" then | |
if timer.timer > timer.delay then | |
timer.action() | |
timer.timer = timer.timer - timer.delay | |
timer.delay = self:resolve_delay(timer.unresolved_delay) | |
if timer.times > 0 then | |
timer.times = timer.times - 1 | |
if timer.times <= 0 then | |
timer.after() | |
self.timers[tag] = nil | |
end | |
end | |
end | |
elseif timer.type == "conditional_every" then | |
local condition = timer.condition() | |
if condition and not timer.last_condition then | |
timer.action() | |
if timer.times > 0 then | |
timer.times = timer.times - 1 | |
if timer.times <= 0 then | |
timer.after() | |
self.timers[tag] = nil | |
end | |
end | |
end | |
timer.last_condition = condition | |
elseif timer.type == "during" then | |
timer.action() | |
if timer.timer > timer.delay then | |
self.timers[tag] = nil | |
end | |
elseif timer.type == "conditional_during" then | |
local condition = timer.condition() | |
if condition then | |
timer.action() | |
end | |
if timer.last_condition and not condition then | |
timer.after() | |
end | |
timer.last_condition = condition | |
elseif timer.type == "tween" then | |
local t = timer.method(timer.timer/timer.delay) | |
for k, v in pairs(timer.source) do | |
timer.target[k] = math.lerp(t, timer.initial_values[k], v) | |
end | |
if timer.timer > timer.delay then | |
timer.after() | |
self.timers[tag] = nil | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment