Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Cooked up a basic event listener manager — Gideros Forum

Cooked up a basic event listener manager

eezingeezing Member
edited February 2014 in Code snippets
*My second update. Previous posts were overly complicated and impractical.

Some simple code to add/remove listeners. Nothing special going on here, I basically wanted the ability to remove all listeners pertaining to a specific sprite in one line.

You'll notice in the 'addListener' function, there is a 'target' parameter. This should be used when the event you're listening for is not dispatched to the sprite handling the listener function.

No additional closures are created so performance of a dispatched event is normal.
MySprite = Core.class(Sprite)
 
function MySprite:addListener(type, listener, data, target)
 
	local store = self.myEventStore or {}
	local target = target or self
 
	if not store[type] then
 
		store[type] = { listener = listener, data = data, target = target }
 
		target:addEventListener(type, listener, data)
	end
 
 
	self.myEventStore = store
end
 
function MySprite:removeListener(type)
 
	local store = self.myEventStore
	local event = store[type]
 
	if store and event then
 
		event.target:removeEventListener(type, event.listener, event.data)
 
		store[type] = nil
 
		self.myEventStore = store
	end
end
 
function MySprite:removeAllListeners()
 
	local store = self.myEventStore
 
	if store then
 
		for type, event in pairs(store) do
 
			event.target:removeEventListener(type, event.listener, event.data)
		end
 
		self.myEventStore = nil	
	end
end
Use like so:
------- Make listener --------
 
-- Make sprite
local sprite = MySprite.new()
 
-- Listener function
local function onEvent(sprite, event)
 
	print(event:getType())
end
 
 
-------- Example A ----------
 
-- Add a Listener
sprite:addListener("goat", onEvent, sprite)
 
-- Dispatch Event: Good!
sprite:dispatchEvent(Event.new("goat"))
 
 
-- Remove Listener
sprite:removeListener("goat")
 
-- Dispatch Event: Nothing!
sprite:dispatchEvent(Event.new("goat"))
 
 
-------- Example B ------------
 
-- Add a couple Listeners
sprite:addListener("beast", onEvent, sprite)
sprite:addListener("cheese", onEvent, sprite)
 
-- Dispatch those events: Good!
sprite:dispatchEvent(Event.new("beast"))
sprite:dispatchEvent(Event.new("cheese"))
 
 
-- Remove all Listeners
sprite:removeAllListeners()
 
-- Dispatch those events: Nothing!
sprite:dispatchEvent(Event.new("beast"))
sprite:dispatchEvent(Event.new("cheese"))
 
 
------ Example C ---------------
 
-- Make another sprite ( note: doesn't have to be MySprtie class )
local otherSprite = Sprite.new()
 
-- Add a Listener to target otherSprite
sprite:addListener("chicken", onEvent, sprite, otherSprite)
 
-- Dispatch event: good!
otherSprite:dispatchEvent(Event.new("chicken"))
 
-- Remove listener for other sprite
sprite:removeListener("chicken")
 
-- Dispatch event: Nothing!
otherSprite:dispatchEvent(Event.new("chicken"))

Likes: talis, aditya

+1 -1 (+2 / -0 )Share on Facebook

Comments

  • john26john26 Maintainer
    pretty impressive! I can see being able to remove all listeners is useful. Not so sure why you would need to have listeners that only fire once? The "manually remove" option seems to be identical to the existing functionality of addEventListener.

    Of course, I'm sure you know, it is not necessary to remove listeners before removing a sprite. Just remove/nil out the sprite and all its listeners die with it. (unless I'm completely wrong...)
  • eezingeezing Member
    edited February 2014
    @ john26

    You're reply got me wondering, so I did some testing and here's what I came up with...

    Yes, if a sprite doesn't exist, then events attached to it will die... but only upon garbage collection. From my experience, garbage collection by default doesn't happen too frequently in cases where memory consumption is low.

    Now... a sprite that doesn't exist means that:

    - It can't be a parent
    - It can't be a child
    - it can't be referenced in a living table or variable

    Here's a sample of what would be required to remove an event listener without manually doing so:
     
    -- Make Sprite & reference elsewhere
    --------------------------------
     
    local sprite = Sprite.new()
    stage:addChild(sprite)
     
    local someTable = {[1] = sprite}
     
    -- Sprite is now a child of stage and
    -- is referenced in some table
     
     
     
    -- Event Listener
    --------------------------------
     
    -- A local on frame function
    local function onFrame(self)
     
    	print(os.clock())
    end
     
    -- Add on frame event listener
    sprite:addEventListener(Event.ENTER_FRAME, onFrame, sprite)
     
     
     
    -- Destroy sprite so event listener will go away automatically
    -------------------------------
     
    -- First, remove table reference
    someTable[1] = nil
     
    -- Second, remove from parent (stage)
    sprite:removeFromParent()
     
    -- Third, nil out sprite
    sprite = nil
     
    -- Fourth, garbage collect!
    collectgarbage("collect")
     
     
    -- Note: If any of the four steps above is 
    -- not done, listener will live on.







  • john26john26 Maintainer
    edited February 2014
    I see your point now. Indeed, I think Gideros dispatches ENTER_FRAME events to all sprites even those not on the display tree. So even if you remove a sprite it may still get and act on events. So you need to kill the event listener. However, I think this does not apply to touch events (i.e. touch events are only dispatched to sprites on the display tree). I've never quite understood why it was designed in this way as it means (if I understood correctly) that sprites that are waiting for garbage collection can still do things which is a bit weird...

    BTW, Longford does not pass any events to sprites which have been removed from the display tree.

    http://www.giderosmobile.com/forum/discussion/4469/introducing-longford-a-partly-gideros-compatible-open-source-game-engine

  • eezingeezing Member
    edited February 2014
    @john26

    Thanks for posting that link. That engine you have there has a lot of nice features. I need to check it out further.

    Btw, can longford export to windows 8 app (windows store)?
  • john26john26 Maintainer
    Well, it can export a stand-alone windows executable which will run on Intel Windows (will not run on Win RT or Windows Phone 8). Basically its written using standard Win32 API which goes back many years and is still supported (at least in the Desktop mode). However, to get the app in the actual Windows Store may need to add some "Metro style" APIs. But since Longford is open source it's possible to add all these things. If you are knowledgeable about Windows 8 (and Win Phone 8) perhaps you could help to do the port? That's the beauty of having an open source project. And Longford should be very portable, most source code files are completely OS agnostic.
Sign In or Register to comment.