Here’s my updated version. I borrowed prioritisation and event “consume” (high priority listeners prevent lower priority callbacks from being called) from @Jmv38 's version
Event = class()
--[[
v 1.2 Events now indexed in an array, not a hash table, allowing them to have an order, priorities, and for high priority listeners to "consume" the dispatched event, preventing lower priority callbacks from being called. To do this, have the callback of a high priority event return true.
very simple event handler, adapted from Cargobot. Event can be made a superclass of the scenes in the game, so that events have a scope,like they do in Corona.
You could just make it a global events manager though.
syntax:
-------
scene:subscribe(event, listener, callback, priority)
priority is optional. Either omit it (for default #events+1 insertion) or set it to 1 for high priority events.
if callback function returns true then it will "consume" the dispatch. Use together with priority 1 events
scene:unsubscribe(event, listener) --listener optional
scene:dispatch(event, arguments)
examples:
---------
scene:subscribe("catMoves", self, self.chase, 1)
--a bug subscribes to event "catMoves", with optional first priority
scene:dispatch("catMoves", self.pos)
--broadcast cat position from hero class to current scene
self:subscribe("tap", self, self.touched)
--a scene subscribes itself to a system event, note repetition of self
notes:
------
the callback is defined in the class in the usual way, ie with a colon
"Bug:chase(arg)", but is given as a callback argument with a period,
and without brackets or arguments "self.chase"
]]
function Event:init()
self.events={}
print("Scene "..self.id.." created\
"..string.rep("=",34))
end
function Event:subscribe(event, listener, callback, pos)
if not self.events[event] then
self.events[event]={} --create event
--print ("Event "..event.." created in "..self.id.."\
"..string.rep("-",34))
end
local pos=pos or #self.events[event]+1
table.insert(self.events[event], pos, {li=listener, cb=callback}) --add listener.
--print (listener.id.." is subscribed to "..event)
end
function Event:unsubscribe(event, listener) --listener optional
if listener then
for i=1,#self.events[event] do
if self.events[event][i].li==listener then
-- print (listener.id.." #"..i..", unsubscribed from "..event)
table.remove(self.events[event], i) --unsubscribe one listener
return
end
end
else
self.events[event]=nil --unsubscribe all listeners
end
end
function Event:dispatch(event,...)
if not self.events[event] then
-- print ("no subscribers to "..event) --error message for debug purposes
return
end
for i,v in ipairs(self.events[event]) do --has to be ipairs because objs can get removed within the draw loop. if count backwards, can no longer set priority 1
-- local v=self.events[event][i]
if v.cb(v.li, unpack(arg)) then return end --return true to halt the dispatch
end
end