Runtime event listener is not running

Currently, I am working on making fireballs flip when they go up, and flip again when they fall back down. However, I discovered my eventListener is not working. (the magic of print statements)

Here is my code:

function instance:flip() local vx, vy = self:getLinearVelocity() print(vy) end instance:addEventListener("flip")

If any code is needed, please ask. Thanks!

You’ve made a coding mistake.    

You are not setting up a Runtime listener  that code sets up an object/table listener.

Either do this:

function instance:flip() local vx, vy = self:getLinearVelocity() print(vy) end Runtime:addEventListener( "flip", instance )

or use SSKand make it easier to read as well as to type:

listen( "flip", instance )

Also, what does your dispatch code look like

This is long hand (yuck):

Runtime:dispatchEvent( { name = "flip" } )

This is SSK (superior for legibility and typing again):

post("flip")

I don’t have any dispatch code. (hope I don’t sound dumb here)

Also, the code you provided did not work.

Note: If there is a syntax error in my code that is one thing, but the code I provided will work fine otherwise.  I do this all the time.

Tip: You need to dispatch an event for it to be reacted to.

Here is fully functional standalone example showing you how to code a runtime event listener (using SSK because I hate typing longhand)

This complete example will put a rectangle on the screen and rotate it using a transition every time you tap the screen.

require "ssk2.loadSSK" \_G.ssk.init() local rect = display.newRect( 100, 100, 100, 100 ) function rect.onFlip( self, event ) table.dump(event) transition.cancel( self ) transition.to( self, { rotation = self.rotation + 45 } ) end; listen( 'onFlip', rect ) local function onTouch( event ) if( event.phase == "ended" ) then post('onFlip') end end listen( "touch", onTouch )

One final note.  You may be making this all more complicated than need be.

If ‘instance’ is in scope at the place in your code where you want to case the ‘flip’  just do this:

instance:flip()

i.e. call the ‘custom’ method flip that you added to instance directly.

Oh, and let’s clarify some terms.

  • The function’flip’ that you added to ‘instance’ is a method because it implies the argument ‘self’

  • You are trying to set up a custom event listener for an event named ‘flip’

  • You have implied you want to listen for and to  dispatch this event in the Runtime (global) space.

  • Alternately, you could dispatch this directly via the object space, but that would be redundant with my example above where I suggest calling the method directly.

Tip: This last point is why I never use the object event dispatch system (except in extremely specialized cases.)  You need the object to be in scope to dispatch in the object space so why not call the method directly?

The power of Runtime events combined with custom event listeners is that you can send ‘events’ into the global space and objects will respond to them, never needing to be directly connected to the calling code or its scope.

There is a danger here too.  Objects with custom event listeners that are listening in the Runtime space can receive events after the object has been destroyed but not yet removed from the Lua memory system.  Thus you may try to manipulate a display object property of a ‘dead’ object.  This will cause a crash.

I solve this in one of two ways:

  • I use a finalize event to remove all runtime listeners from objects.
  • I add validation code at the top of the custom event listener to ensure the object I’m about to operate on is valid otherwise I stop listening for the event.

As always, SSK comes with handy helpers for all of this…

Standalone example modified with finalize solution:

require "ssk2.loadSSK" \_G.ssk.init() local rect = display.newRect( 100, 100, 100, 100 ) function rect.onFlip( self, event ) table.dump(event) transition.cancel( self ) transition.to( self, { rotation = self.rotation + 45 } ) end; listen( 'onFlip', rect ) function rect.finalize( self ) ignoreList( { 'onFlip' }, self ) end; rect:addEventListener("finalize") local function onTouch( event ) if( event.phase == "ended" ) then post('onFlip') end end listen( "touch", onTouch ) display.remove( rect )

Standalone example above with validation code in event listener:

require "ssk2.loadSSK" \_G.ssk.init() local rect = display.newRect( 100, 100, 100, 100 ) function rect.onFlip( self, event ) if( autoIgnore( 'onFlip', self ) ) then return end table.dump(event) transition.cancel( self ) transition.to( self, { rotation = self.rotation + 45 } ) end; listen( 'onFlip', rect ) local function onTouch( event ) if( event.phase == "ended" ) then post('onFlip') end end listen( "touch", onTouch ) display.remove( rect )

Oh, I get it now. The reason why it’s not working is that Corona only provides four default eventListeners:

collision, enterFrame, key, touch

I was finding it odd that my collision was working, but the flip was not. But it turns out, I had named my collision function ‘collision’ hence why it was working.

In the code you provided me above, you can use touch Listeners to dispatch your events. However, my fireball flip does not rely on any touch inputs from the user. So, I learned a bit, but I am still stuck.

Replying to this question:

Why not call the method directly?

The method in question is the one on the runtime listener. I did not make a function to make the asteroid flip, and then put it on another listener, because all I need is one line of code.

function instance:bounce(event) if event.phase == "began" then if event.other.objType == "ricochet" then self:applyLinearImpulse(0, -70, self.x, self.y) end end end function instance:flip() local vx, vy = self:getLinearVelocity() if vy \> 0 then self.xScale = -1 elseif vy \< 0 then self.xScale = -1 end end Runtime:addEventListener("bounce", instance) Runtime:addEventListener("flip", instance)

In this case, what I am asking is where would I place my dispatch statements, because now, the bounce does not work anymore after I changed its name.

instance:collision --> instance:bounce

I might change it back because I could handle all collision from one function. But, I would still like to solve the problem with my flip.

You’ve said some things that are not correct and you’re confusing me a bit…

There are no default listeners.  There are a number of official object events like collision, touch, etc.

regarding where to put what… the only way I’d be able to help is to see the code and I don’t really have time for that.

I’m sorry but I am deep in working on stuff to make $.  Hopefully someone can help with this.

By default, I meant what official object events. I don’t know any of the proper terms.

Plus, I will try to take it from here and figure it out on my own. Thanks for the help.

If anyone else wants to help, please do. 

Finally, they work.

https://www.youtube.com/watch?v=RMXpVGk3now&feature=youtu.be

Thanks for your help @roaminggamer, you pointed me in the right direction.  :smiley:

You’ve made a coding mistake.    

You are not setting up a Runtime listener  that code sets up an object/table listener.

Either do this:

function instance:flip() local vx, vy = self:getLinearVelocity() print(vy) end Runtime:addEventListener( "flip", instance )

or use SSKand make it easier to read as well as to type:

listen( "flip", instance )

Also, what does your dispatch code look like

This is long hand (yuck):

Runtime:dispatchEvent( { name = "flip" } )

This is SSK (superior for legibility and typing again):

post("flip")

I don’t have any dispatch code. (hope I don’t sound dumb here)

Also, the code you provided did not work.

Note: If there is a syntax error in my code that is one thing, but the code I provided will work fine otherwise.  I do this all the time.

Tip: You need to dispatch an event for it to be reacted to.

Here is fully functional standalone example showing you how to code a runtime event listener (using SSK because I hate typing longhand)

This complete example will put a rectangle on the screen and rotate it using a transition every time you tap the screen.

require "ssk2.loadSSK" \_G.ssk.init() local rect = display.newRect( 100, 100, 100, 100 ) function rect.onFlip( self, event ) table.dump(event) transition.cancel( self ) transition.to( self, { rotation = self.rotation + 45 } ) end; listen( 'onFlip', rect ) local function onTouch( event ) if( event.phase == "ended" ) then post('onFlip') end end listen( "touch", onTouch )

One final note.  You may be making this all more complicated than need be.

If ‘instance’ is in scope at the place in your code where you want to case the ‘flip’  just do this:

instance:flip()

i.e. call the ‘custom’ method flip that you added to instance directly.

Oh, and let’s clarify some terms.

  • The function’flip’ that you added to ‘instance’ is a method because it implies the argument ‘self’

  • You are trying to set up a custom event listener for an event named ‘flip’

  • You have implied you want to listen for and to  dispatch this event in the Runtime (global) space.

  • Alternately, you could dispatch this directly via the object space, but that would be redundant with my example above where I suggest calling the method directly.

Tip: This last point is why I never use the object event dispatch system (except in extremely specialized cases.)  You need the object to be in scope to dispatch in the object space so why not call the method directly?

The power of Runtime events combined with custom event listeners is that you can send ‘events’ into the global space and objects will respond to them, never needing to be directly connected to the calling code or its scope.

There is a danger here too.  Objects with custom event listeners that are listening in the Runtime space can receive events after the object has been destroyed but not yet removed from the Lua memory system.  Thus you may try to manipulate a display object property of a ‘dead’ object.  This will cause a crash.

I solve this in one of two ways:

  • I use a finalize event to remove all runtime listeners from objects.
  • I add validation code at the top of the custom event listener to ensure the object I’m about to operate on is valid otherwise I stop listening for the event.

As always, SSK comes with handy helpers for all of this…

Standalone example modified with finalize solution:

require "ssk2.loadSSK" \_G.ssk.init() local rect = display.newRect( 100, 100, 100, 100 ) function rect.onFlip( self, event ) table.dump(event) transition.cancel( self ) transition.to( self, { rotation = self.rotation + 45 } ) end; listen( 'onFlip', rect ) function rect.finalize( self ) ignoreList( { 'onFlip' }, self ) end; rect:addEventListener("finalize") local function onTouch( event ) if( event.phase == "ended" ) then post('onFlip') end end listen( "touch", onTouch ) display.remove( rect )

Standalone example above with validation code in event listener:

require "ssk2.loadSSK" \_G.ssk.init() local rect = display.newRect( 100, 100, 100, 100 ) function rect.onFlip( self, event ) if( autoIgnore( 'onFlip', self ) ) then return end table.dump(event) transition.cancel( self ) transition.to( self, { rotation = self.rotation + 45 } ) end; listen( 'onFlip', rect ) local function onTouch( event ) if( event.phase == "ended" ) then post('onFlip') end end listen( "touch", onTouch ) display.remove( rect )

Oh, I get it now. The reason why it’s not working is that Corona only provides four default eventListeners:

collision, enterFrame, key, touch

I was finding it odd that my collision was working, but the flip was not. But it turns out, I had named my collision function ‘collision’ hence why it was working.

In the code you provided me above, you can use touch Listeners to dispatch your events. However, my fireball flip does not rely on any touch inputs from the user. So, I learned a bit, but I am still stuck.

Replying to this question:

Why not call the method directly?

The method in question is the one on the runtime listener. I did not make a function to make the asteroid flip, and then put it on another listener, because all I need is one line of code.

function instance:bounce(event) if event.phase == "began" then if event.other.objType == "ricochet" then self:applyLinearImpulse(0, -70, self.x, self.y) end end end function instance:flip() local vx, vy = self:getLinearVelocity() if vy \> 0 then self.xScale = -1 elseif vy \< 0 then self.xScale = -1 end end Runtime:addEventListener("bounce", instance) Runtime:addEventListener("flip", instance)

In this case, what I am asking is where would I place my dispatch statements, because now, the bounce does not work anymore after I changed its name.

instance:collision --> instance:bounce

I might change it back because I could handle all collision from one function. But, I would still like to solve the problem with my flip.