Handling event "ended" when touch exits object.

This bug has stalled my finished game, please someone, a guru or corona staff help me with it please.

The bug is that corona doesn’t register “cancel” or “end” event.phase on an object if you keep dragging over the object until you fall from the edges of that object. let me explain the bug with the following simple example…

 local num = 0 local function bugFunc(event) if(event.phase == "began")then num = 1 end --WILL NEVER GET FIRED IF YOU DRAG OVER THE BUTTON UNTIL YOU ARE NOT TOUCHING THE BUTTON ANYMORE if(event.phase == "ended" or event.phase == "cancelled")then num = 0 end end local function bugTester() print(num) end --ButtonA local buttonA = display.newCircle( 150, 150, 50 ) buttonA.name = "buttonA" buttonA.alpha=0.3 buttonA:addEventListener ( "touch", bugFunc ) Runtime:addEventListener("enterFrame", bugTester)

In the above example the variable “num” will be always equal to “1” if you drag over the button until you are not touching the button anymore.

@coolromin,

Not sure how far you want the user to be able to drag before your num value changes, but I think you could use 'event.phase == “moved” ’ to change the num value to anything you’d like.

Nail

@coolromin, what is the actual bug you’re trying to describe? That a touch even which is not happening over the button is not received by the button? The bug would be if the button DID receive the event when the touch event happens outside the button’s borders.

I think what you want is to test for the “moved” phase. If you want the button to be sent ALL touch events once the touch has started on the button, you need to set the event’s focus to that button. Like this:

local btn = display.newCircle( 100, 100, 25 ) function btn:touch(e) if (e.phase == "began") then btn.hasFocus = true display.getCurrentStage():setFocus( btn ) return true elseif (e.target.hasFocus) then if (e.phase == "moved") then -- do what you want here else -- ended/cancelled display.getCurrentStage():setFocus(nil) e.target.hasFocus = false end return true end return false -- returned when the touch event did not start on the btn end btn:addEventListener("touch",btn)

Translating what @horacebury said back to your code:

    local num = 0          local function bugFunc(event)         print(event.phase)         if(event.phase == "began")then             display.getCurrentStage():setFocus(event.target)             num = 1         end                          --WILL NEVER GET FIRED IF YOU DRAG OVER THE BUTTON UNTIL YOU ARE NOT TOUCHING THE BUTTON ANYMORE         if(event.phase == "ended" or event.phase == "cancelled")then             num = 0             display.getCurrentStage():setFocus(nil)         end         return true     end          local function bugTester()         print(num)     end          --ButtonA         local buttonA = display.newCircle( 150, 150, 50 )         buttonA.name = "buttonA"         buttonA.alpha=0.3         buttonA:addEventListener ( "touch", bugFunc )          Runtime:addEventListener("enterFrame", bugTester)

Basically you need to give your button focus.  When you do that, it knows when you leave it to send the ended phase.  Adding those two focus lines makes your code work the way I think you intend for it to work.

Rob

Does that work also with widgets.  I have a button that doesn’t go to “ended” stage if you drag your finger off the button.  How would I do that in this case?

[lua]

onButtonEvent = function (event )

        if event.phase == “began” then

            myButton:scale(1.2,1.2)

            audio.play(click)

   

        elseif    event.phase == “ended” then

            timer.cancel(tmr1)

            storyboard.gotoScene(‘loading’)

          

        end

    end

    myButton = widget.newButton{

        defaultFile = “Replay.png”,

         left = 0,

        top = 65,        

       width =55, height = 50,

         onEvent = onButtonEvent

    }

    group:insert(myButton)

Hi all,

I’m re-naming this thread because it’s not a bug, but rather a behavioral tendency you must handle. The ended phase is never triggered (and has never been) unless the touch ends on that object.

There are ways to handle scenarios where you want an ended phase to be triggered when the touch drifts off the object. One method that comes to mind is placing an invisible but .isHitTestable=true rectangle behind the button, then when a moved phase is detected on that rectangle, you dispatch an ended event back to the button using the dispatchEvent API. This method may not work for all scenarios, but I think it could be placed into use in most cases.

Best regards,

Brent

@coolromin,

Not sure how far you want the user to be able to drag before your num value changes, but I think you could use 'event.phase == “moved” ’ to change the num value to anything you’d like.

Nail

@coolromin, what is the actual bug you’re trying to describe? That a touch even which is not happening over the button is not received by the button? The bug would be if the button DID receive the event when the touch event happens outside the button’s borders.

I think what you want is to test for the “moved” phase. If you want the button to be sent ALL touch events once the touch has started on the button, you need to set the event’s focus to that button. Like this:

local btn = display.newCircle( 100, 100, 25 ) function btn:touch(e) if (e.phase == "began") then btn.hasFocus = true display.getCurrentStage():setFocus( btn ) return true elseif (e.target.hasFocus) then if (e.phase == "moved") then -- do what you want here else -- ended/cancelled display.getCurrentStage():setFocus(nil) e.target.hasFocus = false end return true end return false -- returned when the touch event did not start on the btn end btn:addEventListener("touch",btn)

Translating what @horacebury said back to your code:

    local num = 0          local function bugFunc(event)         print(event.phase)         if(event.phase == "began")then             display.getCurrentStage():setFocus(event.target)             num = 1         end                          --WILL NEVER GET FIRED IF YOU DRAG OVER THE BUTTON UNTIL YOU ARE NOT TOUCHING THE BUTTON ANYMORE         if(event.phase == "ended" or event.phase == "cancelled")then             num = 0             display.getCurrentStage():setFocus(nil)         end         return true     end          local function bugTester()         print(num)     end          --ButtonA         local buttonA = display.newCircle( 150, 150, 50 )         buttonA.name = "buttonA"         buttonA.alpha=0.3         buttonA:addEventListener ( "touch", bugFunc )          Runtime:addEventListener("enterFrame", bugTester)

Basically you need to give your button focus.  When you do that, it knows when you leave it to send the ended phase.  Adding those two focus lines makes your code work the way I think you intend for it to work.

Rob

Does that work also with widgets.  I have a button that doesn’t go to “ended” stage if you drag your finger off the button.  How would I do that in this case?

[lua]

onButtonEvent = function (event )

        if event.phase == “began” then

            myButton:scale(1.2,1.2)

            audio.play(click)

   

        elseif    event.phase == “ended” then

            timer.cancel(tmr1)

            storyboard.gotoScene(‘loading’)

          

        end

    end

    myButton = widget.newButton{

        defaultFile = “Replay.png”,

         left = 0,

        top = 65,        

       width =55, height = 50,

         onEvent = onButtonEvent

    }

    group:insert(myButton)

Hi all,

I’m re-naming this thread because it’s not a bug, but rather a behavioral tendency you must handle. The ended phase is never triggered (and has never been) unless the touch ends on that object.

There are ways to handle scenarios where you want an ended phase to be triggered when the touch drifts off the object. One method that comes to mind is placing an invisible but .isHitTestable=true rectangle behind the button, then when a moved phase is detected on that rectangle, you dispatch an ended event back to the button using the dispatchEvent API. This method may not work for all scenarios, but I think it could be placed into use in most cases.

Best regards,

Brent