4 a0b1acd8 2022-12-18 op -- Copyright (c) 2015 rxi
6 a0b1acd8 2022-12-18 op -- This library is free software; you can redistribute it and/or modify it
7 a0b1acd8 2022-12-18 op -- under the terms of the MIT license. See LICENSE for details.
10 a0b1acd8 2022-12-18 op local tick = { _version = "0.1.1" }
11 a0b1acd8 2022-12-18 op tick.__index = tick
14 a0b1acd8 2022-12-18 op local iscallable = function(x)
15 a0b1acd8 2022-12-18 op if type(x) == "function" then return true end
16 a0b1acd8 2022-12-18 op local mt = getmetatable(x)
17 a0b1acd8 2022-12-18 op return mt and mt.__call ~= nil
20 a0b1acd8 2022-12-18 op local noop = function()
24 a0b1acd8 2022-12-18 op local event = {}
25 a0b1acd8 2022-12-18 op event.__index = event
27 a0b1acd8 2022-12-18 op function event.new(parent, fn, delay, recur, err)
28 a0b1acd8 2022-12-18 op err = err or 0
29 a0b1acd8 2022-12-18 op -- Create and return event
30 a0b1acd8 2022-12-18 op return setmetatable({
31 a0b1acd8 2022-12-18 op parent = parent,
32 a0b1acd8 2022-12-18 op delay = delay,
33 a0b1acd8 2022-12-18 op timer = delay + err,
35 a0b1acd8 2022-12-18 op recur = recur,
40 a0b1acd8 2022-12-18 op function event:after(fn, delay)
41 a0b1acd8 2022-12-18 op -- Error check
42 a0b1acd8 2022-12-18 op if self.recur then
43 a0b1acd8 2022-12-18 op error("cannot chain a recurring event")
45 a0b1acd8 2022-12-18 op -- Chain event
46 a0b1acd8 2022-12-18 op local oldfn = self.fn
47 a0b1acd8 2022-12-18 op local e = event.new(self.parent, fn, delay, false)
48 a0b1acd8 2022-12-18 op self.fn = function()
50 a0b1acd8 2022-12-18 op e.timer = e.timer + self.parent.err
51 a0b1acd8 2022-12-18 op self.parent:add(e)
57 a0b1acd8 2022-12-18 op function event:stop()
58 a0b1acd8 2022-12-18 op tick.remove(self.parent, self)
63 a0b1acd8 2022-12-18 op function tick.group()
64 a0b1acd8 2022-12-18 op return setmetatable({ err = 0 }, tick)
68 a0b1acd8 2022-12-18 op function tick:add(e)
69 a0b1acd8 2022-12-18 op self[e] = true
70 a0b1acd8 2022-12-18 op table.insert(self, e)
75 a0b1acd8 2022-12-18 op function tick:remove(e)
76 a0b1acd8 2022-12-18 op if type(e) == "number" then
77 a0b1acd8 2022-12-18 op -- Remove and return event
81 a0b1acd8 2022-12-18 op self[idx] = self[#self]
82 a0b1acd8 2022-12-18 op table.remove(self)
85 a0b1acd8 2022-12-18 op self[e] = false
86 a0b1acd8 2022-12-18 op for i, v in ipairs(self) do
87 a0b1acd8 2022-12-18 op if v == e then
88 a0b1acd8 2022-12-18 op return self:remove(i)
94 a0b1acd8 2022-12-18 op function tick:update(dt)
95 a0b1acd8 2022-12-18 op for i = #self, 1, -1 do
96 a0b1acd8 2022-12-18 op local e = self[i]
97 a0b1acd8 2022-12-18 op e.timer = e.timer - dt
98 a0b1acd8 2022-12-18 op while e.timer <= 0 do
99 a0b1acd8 2022-12-18 op if e.recur then
100 a0b1acd8 2022-12-18 op e.timer = e.timer + e.delay
102 a0b1acd8 2022-12-18 op self:remove(i)
104 a0b1acd8 2022-12-18 op self.err = e.timer
106 a0b1acd8 2022-12-18 op if not e.recur then
115 a0b1acd8 2022-12-18 op function tick:event(fn, delay, recur)
116 a0b1acd8 2022-12-18 op delay = tonumber(delay)
117 a0b1acd8 2022-12-18 op -- Error check
118 a0b1acd8 2022-12-18 op if not iscallable(fn) then
119 a0b1acd8 2022-12-18 op error("expected `fn` to be callable")
121 a0b1acd8 2022-12-18 op if type(delay) ~= "number" then
122 a0b1acd8 2022-12-18 op error("expected `delay` to be a number")
124 a0b1acd8 2022-12-18 op if delay < 0 then
125 a0b1acd8 2022-12-18 op error("expected `delay` of zero or greater")
127 a0b1acd8 2022-12-18 op -- If, factoring in the timing error, the event should happen *now* the
128 a0b1acd8 2022-12-18 op -- function is immediately called and the error is temporarily carried
129 a0b1acd8 2022-12-18 op -- through. This assures nested events with delays shorter than the update()
130 a0b1acd8 2022-12-18 op -- delta-time do not accumulate error; several nested events with very small
131 a0b1acd8 2022-12-18 op -- delays may end up being called on the same frame. A dummy event is created
132 a0b1acd8 2022-12-18 op -- and returned so :after() still functions correctly.
133 a0b1acd8 2022-12-18 op local d = delay + self.err
134 a0b1acd8 2022-12-18 op if d < 0 then
135 a0b1acd8 2022-12-18 op local err = self.err
138 a0b1acd8 2022-12-18 op self.err = err
139 a0b1acd8 2022-12-18 op return self:add(event.new(self, noop, delay, recur, self.err))
141 a0b1acd8 2022-12-18 op -- Create, add and return a normal event
142 a0b1acd8 2022-12-18 op return self:add(event.new(self, fn, delay, recur, self.err))
146 a0b1acd8 2022-12-18 op function tick:delay(fn, delay)
147 a0b1acd8 2022-12-18 op return self:event(fn, delay, false)
151 a0b1acd8 2022-12-18 op function tick:recur(fn, delay)
152 a0b1acd8 2022-12-18 op return self:event(fn, delay, true)
156 a0b1acd8 2022-12-18 op local group = tick.group()
158 a0b1acd8 2022-12-18 op local bound = {
159 a0b1acd8 2022-12-18 op update = function(...) return tick.update(group, ...) end,
160 a0b1acd8 2022-12-18 op delay = function(...) return tick.delay (group, ...) end,
161 a0b1acd8 2022-12-18 op recur = function(...) return tick.recur (group, ...) end,
162 a0b1acd8 2022-12-18 op remove = function(...) return tick.remove(group, ...) end,
164 a0b1acd8 2022-12-18 op setmetatable(bound, tick)