4 -- Copyright (c) 2015 rxi
6 -- This library is free software; you can redistribute it and/or modify it
7 -- under the terms of the MIT license. See LICENSE for details.
10 local tick = { _version = "0.1.1" }
14 local iscallable = function(x)
15 if type(x) == "function" then return true end
16 local mt = getmetatable(x)
17 return mt and mt.__call ~= nil
20 local noop = function()
27 function event.new(parent, fn, delay, recur, err)
29 -- Create and return event
40 function event:after(fn, delay)
43 error("cannot chain a recurring event")
47 local e = event.new(self.parent, fn, delay, false)
50 e.timer = e.timer + self.parent.err
58 tick.remove(self.parent, self)
64 return setmetatable({ err = 0 }, tick)
75 function tick:remove(e)
76 if type(e) == "number" then
77 -- Remove and return event
81 self[idx] = self[#self]
86 for i, v in ipairs(self) do
94 function tick:update(dt)
95 for i = #self, 1, -1 do
97 e.timer = e.timer - dt
100 e.timer = e.timer + e.delay
115 function tick:event(fn, delay, recur)
116 delay = tonumber(delay)
118 if not iscallable(fn) then
119 error("expected `fn` to be callable")
121 if type(delay) ~= "number" then
122 error("expected `delay` to be a number")
125 error("expected `delay` of zero or greater")
127 -- If, factoring in the timing error, the event should happen *now* the
128 -- function is immediately called and the error is temporarily carried
129 -- through. This assures nested events with delays shorter than the update()
130 -- delta-time do not accumulate error; several nested events with very small
131 -- delays may end up being called on the same frame. A dummy event is created
132 -- and returned so :after() still functions correctly.
133 local d = delay + self.err
139 return self:add(event.new(self, noop, delay, recur, self.err))
141 -- Create, add and return a normal event
142 return self:add(event.new(self, fn, delay, recur, self.err))
146 function tick:delay(fn, delay)
147 return self:event(fn, delay, false)
151 function tick:recur(fn, delay)
152 return self:event(fn, delay, true)
156 local group = tick.group()
159 update = function(...) return tick.update(group, ...) end,
160 delay = function(...) return tick.delay (group, ...) end,
161 recur = function(...) return tick.recur (group, ...) end,
162 remove = function(...) return tick.remove(group, ...) end,
164 setmetatable(bound, tick)