How to create a "keep pressed" event? - "stationary" phase not working

Hi guys!
I’ve been messing around with Corona for 2 days now, and my game is coming along fine!

But I’ve stumbled upon a problem that I couldn’t find a solution in the documentation or forum.

I need to make a button that applies a force to a certain object while it is pressed.
Much like Mario moving forward when you press the right direction on the joystick.

I’ve messed with the sample codes, but none of the examples are good: The events are updated with the “moved” phase in them.
So for my button, I managed to use it by “massaging” it with the mouse :stuck_out_tongue:
There’s a phase in the documentation called “stationary”:

“stationary” a finger is touching the screen but hasn’t moved from the previous event.

But it doesn’t appear to be working.

So, what do you guys recommend me?! What can I do to solve this?

Thanks in advance! [import]uid: 11130 topic_id: 3582 reply_id: 303582[/import]

Hi Gammabeam,
Why do you not try setting a flag, more like an autofire, that keeps moving in that direction till a new flag is set?

I don’t know how you are implementing it, but if you set the flag on the phase began and on phase ended reset the flag, it should work for you…

cheers,

Jayant C Varma [import]uid: 3826 topic_id: 3582 reply_id: 10830[/import]

I managed to do it.
Here’s a step by step explanation, who knows who may be having the same problems: :wink:

I added some functions that apply the force. They’ll be called by a Runtime EnterFrame, so they can be added each frame. There’s one function for each direction (but I know I can may a variable there and use only one).

Then, created the buttons and added the listeners for their touch.

An finally, the Touch function that tests:

  • What mode is on. “began” will add the listener for the enterFrame, and “ended” will remove it.
  • Which button was pressed. This will add/remove the corresponding enterFrame function to make the object move.

Here’s the code:

[lua]-- ENTERFRAME LISTENERS

local kickerMoveLeft = function( event )
kicker:applyForce( kickerSpeed * -1, 0, 0, 0 )
end

local kickerMoveRight = function( event )
kicker:applyForce( kickerSpeed, 0, 0, 0 )
end
– DEFINE UI ENTITIES

local function onTouch( event )
local mode = event.phase
local clickedButton = event.target

print(clickedButton.id)

if “began” == mode then
if clickedButton.id == “left” then
Runtime:addEventListener( “enterFrame”, kickerMoveLeft )
elseif clickedButton.id == “right” then
Runtime:addEventListener( “enterFrame”, kickerMoveRight )
end
elseif “ended” == mode or “cancelled” == mode then
if clickedButton.id == “left” then
Runtime:removeEventListener( “enterFrame”, kickerMoveLeft )
elseif clickedButton.id == “right” then
Runtime:removeEventListener( “enterFrame”, kickerMoveRight )
end
end

return true
end

local bt_moveLeft = ui.newButton{ default=“buttonMove.png”, x=100, y=510 }
local bt_moveRight = ui.newButton{ default=“buttonMove.png”, x=270, y=510 }
local bt_shoot = ui.newButton{ default=“buttonShoot.png”, x=860, y=510 }
bt_moveLeft.id = “left”
bt_moveRight.id = “right”
bt_shoot.id = “shoot”

bt_moveLeft:addEventListener( “touch”, onTouch )
bt_moveRight:addEventListener( “touch”, onTouch )
bt_shoot:addEventListener( “touch”, onTouch )[/lua]

It works fine in the simulator!
Right now I can’t test it in the device, so I don’t know if the multitouch will work.
Maybe because of the “elseifs”, the game will only receive one input.

If someone reads this, please tell me what you think. It worked, but if there’s a better solution, I want to try it!! :wink: [import]uid: 11130 topic_id: 3582 reply_id: 10854[/import]

@Jayant
Hmmm I’m not sure I understand how to do it… [import]uid: 11130 topic_id: 3582 reply_id: 10855[/import]

Hi Gamabeam,
I am not sure if you need to change EventListeners. You need to employ the stateMachine. OK, in simple english…

local kickerDirection = 0  
  
..  
  
if "began" == mode then  
 if clickedButton.id == "left" then  
 kickerDirection = -1  
 elseif clickedButton.id == "right" then  
 kickerDirection = 1  
elseif "ended" == mode or "cancelled" == mode then  
 kickerDirection=0  
end  
  
local kickerMove = function( event )  
 if kickerDirection == 0 then return end  
  
 kicker:applyForce( kickerSpeed \* kickerDirection, 0, 0, 0 )  
  
end  
  
...  
  
Runtime:addEventListener( "enterFrame", kickerMove )  

so what this code will do is it will keep running the kickerMove function, the moment you release it, it will not move as we check for the condition 0 and return from the function. This should give you what you are after.

You can have states and check for things accordingly.
hope this helps,

cheers,

Jayant C Varma [import]uid: 3826 topic_id: 3582 reply_id: 10856[/import]

Hey Jayant!
I like how your code is more tidy then what I did, but wouldn’t it be more heavy on the performance?

I mean, the listener will be running on each frame even if nothing happens to the object.
I’ll try this code on the game when I go back to my Mac, but it looks like it would work nicely! [import]uid: 11130 topic_id: 3582 reply_id: 10864[/import]

I’ve also found that stationary is not fired. Have reported it as a bug! [import]uid: 9371 topic_id: 3582 reply_id: 12260[/import]

Unfortunately the documentation is misleading. Corona merely relays the phases from the underlying OS. The Corona “stationary” phase corresponds to the iOS UITouchPhaseStationary which only arises in certain multitouch situations. We will update the docs. Sorry for the confusion! [import]uid: 6787 topic_id: 3582 reply_id: 12676[/import]