How to adjust fire rate when touch

I am fiddling around with the tutorial game (star explorer) and wanted to change the method of firing.  Currently it uses the below method :

addEventListener("tap", fireLaser) 

but I want to use the touch method so that I may tap and hold it.  While holding I want it to continue to fire. I simply changed the above to:

ship:addEventListener( "touch", fireLaser )

I have 2 problems, and if they could be answered seperately to help me determine what is happening that would be great. 

Problem 1.  When using the touch method, it is firing extremely rapidly.  I would love the ability to adjust the rate at which it fires while being held.  Any ideas? 

Problem 2.  How do I get it to have the addEventListener to the ship and anything else on the screen (except future buttons).  Meaning, how can I click and  hold in the middle of the screen and it work instead of having to click specifically on the ship.  

The above event listener is located in my scebe:Create right now according to the tutorial.  

Below is the text that runs when it runs the function firelaser incase you need it. 

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

For those reading, he means the marketplace item: https://marketplace.coronalabs.com/asset/star-explorer

I’ll check back later and try to answer if this has not been answered by then.

* UPDATED *

@Klynt 

Welcome to the community.   Thanks so much for formatting that code post!

When referring to blog posts, assets, etc. here on the site, please supply a link.  It saves us having to look it up to help you. 

Cheers,

Ed

Can you post your touch listener?

As for the second question, I tend to create an invisible rectangle as big as I want my touch area to be and add your touch listener to the rectangle. There are a couple of things you need to do to make it work:

local fireButton = display.newRect(display.contentCenterX, display.actualContentHeight / 3 \* 2, display.actualContentWidth, display.actualContentHeight / 3 fireButton.isVisible = false fireButton.isHitTestable = true

And to help others, in addition to Ed’s marketplace link, please refer to our Getting Started Guide:

https://docs.coronalabs.com/guide/programming/index.html

Rob

My touch sensor is currently just the following, located in the scene:create section. 

ship:addEventListener( "touch", fireLaser )

I assume i need to maybe add a (hasBeenFiredRecently) and a (lastFiredTime) and then require a countdown based on time or something.  

I was hoping you would post this function: fireLaser

Our touch event only generates events when the touch begins, ends, or detects a move.  We have this tutorial for adapting our touch listener to do continuous fire events:  https://docs.coronalabs.com/tutorial/events/continuousActions/index.html

But basically, you need to have a variable that tracks the last time you fired and wait until X amount of time has elapsed before you fire again.

Rob

Rob, thanks for the help. The firelaser function was posted in the OP. I was trying what you recommended last night but I was using os.time but that onlY does seconds. Hopefully this method you linked can allow for shorter durations. Ill give it a try over the next couple nights

The codes below will help you to adjust the fire rate.

local function onTouch(event)
    local phase = event.phase

    if phase == “began” then
        local function fireLaser()
            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()

            – Play fire sound!
            audio.play( fireSound, {loops=-1} )
 
            transition.to( newLaser, { y=-40, time=500,
                onComplete = function() display.remove(newLaser); end
            } )
        end

        laserTimer = timer.performWithDelay(t, fireLaser, -1)

        audioTimer = timer.performWithDelay(t, function() audio.play(fireSound); end, -1)

    elseif phase == “ended” then
        timer.pause(laserTimer)

        timer.pause(audioTimer)
    end
end

fireButton:addEventListener(“touch”, onTouch)
 
In “t” set your desired delay time.

There are a couple of things. First, “newLaser” seems to be a global variable that you’re destroying when the transition completes. You never re-add the touch handler. This is why I recommend an invisible button as suggested above to have your touch handler. You should make newLaser local. In your transition’s onComplete event.target will be that specific laser blast that you can remove.

As far as the time for “t”, 16.6667 is probably the lowest for a 30fps app. Beyond that, your timer is firing faster than the screen is updating.

Rob

Alright, so I applied most of what saifuls.ctg89 recommended.  I was able to control the speed by varying the bulletTimer (“t”).  I didn’t do the invisible button yet, I will work on that next.  The issue I am currently having is that after holding the “touch” for various times (between half second and 1 second typcially) it starts to cut my bullet travel distance (transition.to distance) to… like really small (maybe 1/4th of the screen".  Any idea on why that is happening? 

Lastly, I am wanting to keep the drag function as well, but use this newly defined BOX to control the travel of the ship.  Currently, I have it so that when clicking in the box I can drag it, but if I stop touching and then retouch, it restarts my ship into the center of the screen (teleports it there if it isn’t already).  Any ideas?

Below is my code.  

--This is the code for my onTouch, which is triggered when touching the box. local function onTouch(event) local phase = event.phase local newLaser if phase == "began" then local function fireLaser() 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() -- Play fire sound! audio.play( fireSound, {loops=-1} ) transition.to( newLaser, { y=-40, time=1000, onComplete = function() display.remove( newLaser ) end } ) end bulletTimer = timer.performWithDelay(200, fireLaser, -1) elseif phase == "ended" then timer.cancel(bulletTimer) end end

-- This is the info for the fireButton (or invisible rectangle) located in the function scene:create( event ) local fireButton = display.newRect(display.contentCenterX, display.actualContentHeight / 3 \* 2, display.actualContentWidth, display.actualContentHeight +100) fireButton.isVisible = false fireButton.isHitTestable = true fireButton:addEventListener( "touch", dragShip ) fireButton:addEventListener("touch", onTouch)

--This is the code I am currently using for dragShip local function dragShip( event ) local box = event.target local phase = event.phase if ( "began" == phase ) then -- Set touch focus on the ship display.currentStage:setFocus( box ) -- Store initial offset position ship.touchOffsetX = event.x - box.x elseif ( "moved" == phase ) then -- Move the ship to the new touch position ship.x = event.x - ship.touchOffsetX elseif ( "ended" == phase or "cancelled" == phase ) then -- Release touch focus on the ship display.currentStage:setFocus( nil ) end return true -- Prevents touch propagation to underlying objects end

--Lastly, this is how ship is defined (in the scene:create(event) section) ship = display.newImageRect( mainGroup, objectSheet, 4, 98, 79 ) ship.x = display.contentCenterX ship.y = display.contentHeight - 100 physics.addBody( ship, { radius=30, isSensor=true } ) ship.myName = "ship"

Try this.

local fireButton = display.newRect(display.contentCenterX, display.actualContentHeight / 3 * 2, display.actualContentWidth, display.actualContentHeight +100)

fireButton:toFront()
fireButton.isVisible = false
fireButton.isHitTestable = true

local function dragShip( event )

    local fireButton = event.target

    local phase = event.phase

    if ( “began” == phase ) then

        – Set touch focus on the fireButton

        display.currentStage:setFocus( fireButton )

        – Store initial offset position

        fireButton.touchOffsetX = event.x - ship.x

    elseif ( “moved” == phase ) then

        – Move the ship to the new touch position

        ship.x = event.x - fireButton.touchOffsetX

    elseif ( “ended” == phase or “cancelled” == phase ) then

        – Release touch focus on the fireButton

        display.currentStage:setFocus( nil )

    end

    return true – Prevents touch propagation to underlying objects

end

Thanks, that helped fix my movement issue. Any ideas on why my bullets start to fire full length and then after a half second/second, they begin only going about 1/4 of the screen?

--Fire button located in Scene:create( event ) local fireButton = display.newRect(display.contentCenterX, display.actualContentHeight / 3 \* 2, display.actualContentWidth, display.actualContentHeight + 100) fireButton:toFront() fireButton.isVisible = false fireButton.isHitTestable = true

--This function fires the bullet local function onTouch(event) local phase = event.phase local newLaser if phase == "began" then local function fireLaser() 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() -- Play fire sound! audio.play( fireSound, {loops=1} ) transition.to( newLaser, { y=-40, time=1000, onComplete = function() display.remove( newLaser ) end } ) end bulletTimer = timer.performWithDelay(200, fireLaser, -1) --The 200 is the rate of fire, fastest posisble is 17 elseif phase == "ended" then timer.cancel(bulletTimer) end end

It’s for 60 fps app. Cause 1000 ms = 1 s. 1000 / 60 = 16.67.

Dunno where’s the prob… It worked fine for me. By the way the lowest interval depends on the fps of the app (I should’ve mentioned before).

Ok… I guess I’ll remove all the other code I have to see if it works for me and start to add to it to see what is effecting it.

Goodluck bro. By the way I edited the post posted earlier (Controlling the fire rate). Check it out.

Edited:

local function onTouch(event)
    local phase = event.phase

    if phase == “began” then
        local function fireLaser()
            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()

            – Play fire sound!
            audio.play( fireSound, {loops=-1} )
 
            transition.to( newLaser, { y=-40, time=500,
                onComplete = function() display.remove(newLaser); end
            } )
        end

        laserTimer = timer.performWithDelay(t, fireLaser, -1)

        audioTimer = timer.performWithDelay(t, function() audio.play(fireSound); end, -1)

    elseif phase == “ended” then
        timer.pause(laserTimer)

        timer.pause(audioTimer)
    end
end

fireButton:addEventListener(“touch”, onTouch)
 
In “t” set your desired delay time.

AHHHH, this creates unending sound audio again.  The last one you posted did the same so I had to edit it.  currently the one I use does 2 sounds for some reason, but it doesn’t make super loud unending audio.  thoughts?

So I tried to remove stuff and figure it out, but I am getting the same thing… This is a youtube video showing what is happening. 

https://youtu.be/X_Lpbl2ZpHs 

Ok, so i figured out the problem line… i just don’t understand why it’s not working. 

 transition.to( newLaser, { y=-40, time=500, onComplete = function() display.remove( newLaser ) end } )

This set of code is causing the issue… specifically, the onComplete section.  If I comment out that line, it works great (except it never removes the lasers).  

I think this has something to do with once other lasers make it to that -40 or (Completion point) , it is deleting all of the lasers and continues to do so until released.  Since I am using a touch event instead of tap this seems to be causing an issue.  

So, to fix this… do I need to make a table and keep track of these lasers some how and delete them in a timeloop or something?  

Hey guys.  You’re doing this wrong.  You need to stop a channel.

See my second to last post in this thread (posted at 1:25 pm):

https://forums.coronalabs.com/topic/70793-how-to-stop-a-audio-after-it-has-finished/