How to adjust fire rate when touch

is there something wrong with just calling the audio.play() each time I fire?  I am not sure what the reason behind the loop is.  

This is what I am using now (for sound) and it seems to work fine as best I can tell. 

local function onTouch(event) local phase = event.phase local newLaser if phase == "began" then local function fireLaser() -- Play fire sound! audio.play( fireSound ) 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=-100, time=500, 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 if bulletTimer then timer.cancel(bulletTimer) end end end

This is purely a suggestion that I put together blind, but I hope it approximates what you’re trying to do.

ORIGINAL

-- -- ORIGINAL -- 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 ship:addEventListener( "tap", fireLaser )

SUGGESTION

-- -- REPLACEMENT - Not Perfect; But should work OK... (may contain typos) -- -- NOTE: Assumes you already loaded the sound 'fireSound' local laserChannel = audio.findFreeChannel() -- Find a free channel to play sounds on audio.reserveChannels( laserChannel ) -- Lock it for use by laser sound ONLY. local firePeriod = 100 -- one shot every 100 ms ==\> 10 shot per second local lastTime = system.getTimer() local function fireLaser() audio.stop( laserChannel ) audio.play( fireSound, { channel = laserChannel } ) 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 local function onEnterFrame( self ) if( ship.firing ) then local curTime = system.getTimer() local dt = lastTime - curTime if( dt \>= firePeriod ) then fireLaser() end end end local function onTouch( self, event ) local phase = event.phase local id = event.id if phase == "began" then display.getCurrentStage():setFocus( self, id ) self.isFocus = true self.firing = true elseif self.isFocus then if phase == "ended" then display.getCurrentStage():setFocus( self, nil ) self.isFocus = false self.firing = false audio.stop( laserChannel ) end end return false end ship.touch = onTouch ship.enterFrame = onEnterFrame ship:addEventListener( "touch" ) Runtime:addEventListner( "enterFrame", ship )

So the problem occurred because you made the newLaser var. local outside of the fireLaser function. Make inside of it. (Actually it was my mistake. But I edited the post later.)

OMG, silly me… thanks! that fixed it.  You guys are awesome. 

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?