Need help with EventListener.

How can I change this statement to be a continues actions instead of tapping. 

ship:addEventListener( “tap”, fireLaser )

ex: game starts and the laser automatically begins to fire.

Don’t use tap events. 

Use:

  • touch event - Superior to tap and flexible.
    • my example
      • fires/stop laser
      • creates/destroys laser
      • moves player
  • enterFrame - to move laser with player if player is moving
  • finalize - to remove enterframe when player is destroyed.

All functions I used below can be found on or via API page: https://docs.coronalabs.com/api/

May contain typos:

local cx = display.contentCenterX local cy = display.contentCenterY local player = newRect( cx, cy, 20, 20 ) function player.enterFrame( self ) if( not self.laser ) then return end self.laser.x = self.x self.laser.y = self.y end Runtime:addEventListener("enterFrame", player) function player.finalize( self ) Runtime:removeEventListener("enterFrame", self) end player:addEventListener("finalize") function player.touch( self, event ) local eventID = event.id self.x = event.x self.y = event.y if(event.phase == "began") then display.getCurrentStage():setFocus( self, eventID ) self.isFocus = true print("START FIRING") self.laser = display.newRect( self.x, self.y, 6, 1000 ) self.laser.anchorY = 0 self.laser:setFillColor(1,0,0) self:toFront() elseif(target.isFocus ) then if(event.phase == "ended" or event.phase == "cancelled") then display.getCurrentStage():setFocus( self, nil ) self.isFocus = false print( "STOP FIRING" ) display.remove(self.laser) self.laser = nil end end return true end player:addEventListener("touch")

Tip: I used a rectangle instead of a line for the laser because I knew you ‘might’ want to add a body.

Moving bodies this way isn’t great, but will work OK.

Im having a hard time understanding what you posted…

here’s an example of what I’m doing

local function fireLaser() -- Play fire sound! audio.play( fireSound ) local newLaser = display.newImageRect( mainGroup, objectSheet, 5, 14, 40 ) physics.addBody( newLaser, "dynamic", { isSensor=true } ) newLaser.isBullet = true newLaser.myName = "laser" newLaser.x = ship.x newLaser.y = ship.y newLaser:toBack() transition.to( newLaser, { y=-40, time=500, onComplete = function() display.remove( newLaser ) end } ) end

and then

ship:addEventListener( "tap", fireLaser ) 

Im following the tutorial in the learning section. 

I tried understanding what you sent but couldn’t make sense of it.

Sorry.  I’ll let some else follow up on this.  I’m not familiar with the tutorials.  They are after my time here and I’ve never run through them.

The example I gave you is highly complete, but uses advanced concepts and may not be compatible with the tutorials without changes.

You can remove:

  • enterframe code
  • finalize code
  • player movement in touch
  • laser creation code in touch

Then, you will be left with a touch listener that knows when to create and destroy a laser.

Hopefully, you can work from there.

function player.touch( self, event ) local eventID = event.id if(event.phase == "began") then display.getCurrentStage():setFocus( self, eventID ) self.isFocus = true print("START FIRING") -- DO START FIRING WORK HERE elseif(target.isFocus ) then if(event.phase == "ended" or event.phase == "cancelled") then display.getCurrentStage():setFocus( self, nil ) self.isFocus = false print( "STOP FIRING" ) -- DO STOP FIRING WORK HERE end end return true end player:addEventListener("touch")

I figured it out!! 

I tried  ship:addEventListener( “touch”, fireLaser )  but all that did was shoot endlessly every time the ship was moved…

The solution was to simply, add a time delay with the **local function fireLaser() **in it.

For anyone that would like to try this here is the set up I had for the tutorial.

local function fireLaser() -- Play fire sound! audio.play( fireSound ) local newLaser = display.newImageRect( mainGroup, objectSheet, 5, 14, 40 ) physics.addBody( newLaser, "dynamic", { isSensor=true } ) newLaser.isBullet = true newLaser.myName = "laser" newLaser.x = ship.x newLaser.y = ship.y newLaser:toBack() transition.to( newLaser, { y=-40, time=500, onComplete = function() display.remove( newLaser ) end } ) end timer.performWithDelay( 500, fireLaser, 0 )

and make sure to delete

ship:addEventListener( “touch”, fireLaser )

Turns out this method conflicts with the firelaser function . So still looking for a way to make this work.

These questions are so difficult to answer on a forum!

The premise of “tap my ship and fire a single laser” is absolutely a candidate for a tap event. Note the emphasis on single.  And tap handler will raise a single event.

Now say you want to simulate continual movement then a tap event is all wrong as @rg points out.  For this a touch event combined with enterFrame is the way forward.

Mixing transition and physics is a major no… you want to apply a force to the object (to move it).

There is no “here is the answer” to this kinda problem as the scope is simply massive.

SGS… Don’t I know it!.

ricmontalvan … there’s a few different ways to do this, here is what I use:

  1. every time you fire a laser you add a laser object into a laserObject table. 

  2. In your enterframe event handler, you loop through this table and move each laser object one at a time calculating angle, velX and velY

  3. To repeat fire, I do this on a touch event:

if shootTapTimer == nil and cooldownTimer == nil then
      shootPrimary()
      shootTapTimer = timer.performWithDelay(shootDelay, function() shootPrimary() end ,0)
 end

function shootPrimary()

local torpedo = display.newSprite( torpSheet, torpSequence )
    torpedo.objTable = torpedotable
    torpedo.index = #torpedo.objTable + 1
    torpedo.objTable[torpedo.index] = torpedo
    torpedo.id = “torpedo”
    torpedo.range = weaponDischargeRate[1][3]
    torpedo.CvelX = player.velX
    torpedo.CvelY = player.velY

    torpedo.x =player.x + 50 * math.cos((player.rotation)* (mPi/180))
    torpedo.y= player.y + 50 * math.sin((player.rotation)* (mPi/180))
   

and in my event loop I calculate velX and velY:

   local accel = 5
   local tangle = torpedotable[i].rotation   * -1
   torpedotable[i].CvelX = torpedotable[i].CvelX + math.sin(math.rad(tangle)) * (accel)
   torpedotable[i].CvelY = torpedotable[i].CvelY + math.cos(math.rad(tangle)) * (accel)
   local spd = math.abs(torpedotable[i].CvelX) + math.abs(torpedotable[i].CvelY)      

I’m going to have to learn a bit more of the basics before I integrate this into my app 🤷

Don’t use tap events. 

Use:

  • touch event - Superior to tap and flexible.
    • my example
      • fires/stop laser
      • creates/destroys laser
      • moves player
  • enterFrame - to move laser with player if player is moving
  • finalize - to remove enterframe when player is destroyed.

All functions I used below can be found on or via API page: https://docs.coronalabs.com/api/

May contain typos:

local cx = display.contentCenterX local cy = display.contentCenterY local player = newRect( cx, cy, 20, 20 ) function player.enterFrame( self ) if( not self.laser ) then return end self.laser.x = self.x self.laser.y = self.y end Runtime:addEventListener("enterFrame", player) function player.finalize( self ) Runtime:removeEventListener("enterFrame", self) end player:addEventListener("finalize") function player.touch( self, event ) local eventID = event.id self.x = event.x self.y = event.y if(event.phase == "began") then display.getCurrentStage():setFocus( self, eventID ) self.isFocus = true print("START FIRING") self.laser = display.newRect( self.x, self.y, 6, 1000 ) self.laser.anchorY = 0 self.laser:setFillColor(1,0,0) self:toFront() elseif(target.isFocus ) then if(event.phase == "ended" or event.phase == "cancelled") then display.getCurrentStage():setFocus( self, nil ) self.isFocus = false print( "STOP FIRING" ) display.remove(self.laser) self.laser = nil end end return true end player:addEventListener("touch")

Tip: I used a rectangle instead of a line for the laser because I knew you ‘might’ want to add a body.

Moving bodies this way isn’t great, but will work OK.

Im having a hard time understanding what you posted…

here’s an example of what I’m doing

local function fireLaser() -- Play fire sound! audio.play( fireSound ) local newLaser = display.newImageRect( mainGroup, objectSheet, 5, 14, 40 ) physics.addBody( newLaser, "dynamic", { isSensor=true } ) newLaser.isBullet = true newLaser.myName = "laser" newLaser.x = ship.x newLaser.y = ship.y newLaser:toBack() transition.to( newLaser, { y=-40, time=500, onComplete = function() display.remove( newLaser ) end } ) end

and then

ship:addEventListener( "tap", fireLaser ) 

Im following the tutorial in the learning section. 

I tried understanding what you sent but couldn’t make sense of it.

Sorry.  I’ll let some else follow up on this.  I’m not familiar with the tutorials.  They are after my time here and I’ve never run through them.

The example I gave you is highly complete, but uses advanced concepts and may not be compatible with the tutorials without changes.

You can remove:

  • enterframe code
  • finalize code
  • player movement in touch
  • laser creation code in touch

Then, you will be left with a touch listener that knows when to create and destroy a laser.

Hopefully, you can work from there.

function player.touch( self, event ) local eventID = event.id if(event.phase == "began") then display.getCurrentStage():setFocus( self, eventID ) self.isFocus = true print("START FIRING") -- DO START FIRING WORK HERE elseif(target.isFocus ) then if(event.phase == "ended" or event.phase == "cancelled") then display.getCurrentStage():setFocus( self, nil ) self.isFocus = false print( "STOP FIRING" ) -- DO STOP FIRING WORK HERE end end return true end player:addEventListener("touch")

I figured it out!! 

I tried  ship:addEventListener( “touch”, fireLaser )  but all that did was shoot endlessly every time the ship was moved…

The solution was to simply, add a time delay with the **local function fireLaser() **in it.

For anyone that would like to try this here is the set up I had for the tutorial.

local function fireLaser() -- Play fire sound! audio.play( fireSound ) local newLaser = display.newImageRect( mainGroup, objectSheet, 5, 14, 40 ) physics.addBody( newLaser, "dynamic", { isSensor=true } ) newLaser.isBullet = true newLaser.myName = "laser" newLaser.x = ship.x newLaser.y = ship.y newLaser:toBack() transition.to( newLaser, { y=-40, time=500, onComplete = function() display.remove( newLaser ) end } ) end timer.performWithDelay( 500, fireLaser, 0 )

and make sure to delete

ship:addEventListener( “touch”, fireLaser )

Turns out this method conflicts with the firelaser function . So still looking for a way to make this work.

These questions are so difficult to answer on a forum!

The premise of “tap my ship and fire a single laser” is absolutely a candidate for a tap event. Note the emphasis on single.  And tap handler will raise a single event.

Now say you want to simulate continual movement then a tap event is all wrong as @rg points out.  For this a touch event combined with enterFrame is the way forward.

Mixing transition and physics is a major no… you want to apply a force to the object (to move it).

There is no “here is the answer” to this kinda problem as the scope is simply massive.

SGS… Don’t I know it!.

ricmontalvan … there’s a few different ways to do this, here is what I use:

  1. every time you fire a laser you add a laser object into a laserObject table. 

  2. In your enterframe event handler, you loop through this table and move each laser object one at a time calculating angle, velX and velY

  3. To repeat fire, I do this on a touch event:

if shootTapTimer == nil and cooldownTimer == nil then
      shootPrimary()
      shootTapTimer = timer.performWithDelay(shootDelay, function() shootPrimary() end ,0)
 end

function shootPrimary()

local torpedo = display.newSprite( torpSheet, torpSequence )
    torpedo.objTable = torpedotable
    torpedo.index = #torpedo.objTable + 1
    torpedo.objTable[torpedo.index] = torpedo
    torpedo.id = “torpedo”
    torpedo.range = weaponDischargeRate[1][3]
    torpedo.CvelX = player.velX
    torpedo.CvelY = player.velY

    torpedo.x =player.x + 50 * math.cos((player.rotation)* (mPi/180))
    torpedo.y= player.y + 50 * math.sin((player.rotation)* (mPi/180))
   

and in my event loop I calculate velX and velY:

   local accel = 5
   local tangle = torpedotable[i].rotation   * -1
   torpedotable[i].CvelX = torpedotable[i].CvelX + math.sin(math.rad(tangle)) * (accel)
   torpedotable[i].CvelY = torpedotable[i].CvelY + math.cos(math.rad(tangle)) * (accel)
   local spd = math.abs(torpedotable[i].CvelX) + math.abs(torpedotable[i].CvelY)      

I’m going to have to learn a bit more of the basics before I integrate this into my app 🤷