In some apps, you’ll need to perform some continuous action while the user’s touch remains on the screen. This could include a character running while the player holds down a “run” button, a space ship firing its lasers while the player’s finger is down, or some action being performed while the player holds the X button on a game controller.

For beginner developers, this process can be elusive because Corona’s event system generates a single event when the screen is touched or a controller button is pressed. Another event is generated when the user lifts off the screen, and of course an event can be generated on each small increment that the touch moves across the screen. However, if the touch remains down and no movement is registered, additional events are not triggered.

To overcome this, let’s explore some techniques to implement continuous actions.

Graphic Button with a Touch Handler

One classic example is a ”fire” button in a space shooter where the ship should fire lasers as long as the button is touched.

First, lets define our fireLasers() function.  It will create a single bullet and launch it towards it’s target.

For this implementation, you may create a basic graphic and attach a touch listener:

When you touch the button, the “began” phase is triggered and the fireLasers() function is called once (but not repeatedly, since the “began” phase only occurs when the touch begins). Thus, to make the lasers fire constantly, you may create a Runtime enterFrame function and use “flags” to control if it should be firing the lasers or not. Let’s look at the modified code:

With this code, while the player’s touch remains on the button, the flag needToFire remains true and, in the Runtime listener function, it continuously fires the weapon. Of course, depending on your app’s settings, this is going to occur at a rate of either 30 or 60 times per second, so you should put in some control to limit how fast the actual laser beams fire.

Implementation with widget.newButton()

This is almost identical to the method above, but the button is set up a bit differently:

widget.newButton() and its onEvent handler behave almost exactly like the previous example, so it allows you to use the same handleFireButton() function. Alternatively, you could use the onPress and onRelease events instead, but this involves two functions: one to set the needToFire flag and another to stop it:

Handling the “Slide Off”

Both of the examples above (graphical button and widget-based button) handle the “began” and “ended” phases of the touch — when the user presses the button, the lasers begin to fire, and when the user lifts off the button, the lasers stop. However, there is a very important case which you must account for: the “slide off” case.

As we’ve discussed, Corona generates an “ended” phase when the user’s touch lifts off the button, but this only occurs if the touch point is actually over the button when the user lifts off. Corona will not generate an “ended” event if the users touches the button and then slides their finger outside of the button content bounds. Thus, unless we account for this, the user could potentially slide outside of the button bounds, lift their finger off, and the lasers would continue firing!

The Solution…

One method of handling the “slide off” case is to place a slightly larger, invisible sensory object behind the button which only senses the “moved” phase. For simplicity in this example, we’ll make it a vector rectangle:

Basically, this invisible object detects any “moved” phase upon it. In most cases, the touch probably began on the button and then slid off the button onto the sensor. This generates a “moved” phase on the rectangle, not a “began” phase. Secondly, this function checks that needToFire is true before toggling it back to false — this handles the alternate possibility that the user touched somewhere outside of the button and then slid onto the sensory rectangle. This case should effectively do nothing, and our conditional handling takes this into account since needToFire will be false unless a press on the button toggles it to true.

There are two additional things to note with this sensory object:

  1. Note that you must set the .isHitTestable property on the object to true. By default, invisible objects do not receive touch/tap events, so you must set this property to true to ensure that the object recognizes touch events.
  2. Remember to place the object behind the button in z-index ordering, either by creating the sensory object before creating the button, or pushing it to the back of its display group via object:toBack().

Using a Game Controller

Game controllers also generate singular events when a button is pressed or released, so you must handle them similarly:

Timer Versus Runtime Listener

You might find that a timer is easier to work with than a Runtime listener, especially since you’ll almost certainly be limiting the rate of laser fire. Using timers, the code may be refactored like this:

In Summary

Hopefully, this tutorial has provided a foundation for handling continuous actions in Corona SDK. This practice may apply to many scenarios beyond the “laser fire” that we’ve presented. With a little creativity, the sky is the limit!

Continue at source:

Tutorial: Continuous Actions in Corona