[RESOLVED] Cannot delay function that adds listener!

In my program, I have card images that have listeners which allow them to be dragged (via cv.dragCard). I also use a function (cv.resetCard) that resets such cards, removing focus from them and putting them back into their original position (assuming that image isn’t supposed to be moved elsewhere or removed all together, etc) when a touch event is ended or cancelled.

However, I’ve noticed when accidentally tapping again while letting go of a card (thus touching it mid-transition), a new touch event is registered and it gets positioned there instead (terrible). So my proposed solution is to temporarily remove the listener while the card transitions. However I have tried this using two approaches and neither works.

The first is:

[lua]

function cv.resetCard( target, moveBack )

    cv.removeListener( target )

    – Resets focus.

    display.getCurrentStage():setFocus( nil )

    target.isFocus = false

    – Snaps back to original position.

    if moveBack == true then

        transition.to(target,{time=100, x=target.xO, y=target.yO, onComplete=cv.addListener( target ) })

    else end

end

[/lua]

And the second is (NOTE: only change is using timer.performWithDelay instead of onComplete within transition.to):

[lua]

function cv.resetCard( target, moveBack )

    cv.removeListener( target )

    – Resets focus.

    display.getCurrentStage():setFocus( nil )

    target.isFocus = false

    – Snaps back to original position.

    if moveBack == true then

        transition.to(target,{time=100, x=target.xO, y=target.yO })

        timer.performWithDelay( 100, cv.addListener( target ) )

    else end

end

[/lua]

But both have the same result: the listener is re-added immediately instead of waiting so the problem persists. Any ideas why? I vaguely recall reading about a similar issue when applying and removing listeners within an event function, however I thought the solution to that was to do so via separate functions (which I am doing here)…

A few other notes if pertinent:

The functions cv.addListener and cv.removeListener do nothing but target:addEventListener( “touch”, cv.dragCard ) and target:removeEventListener( “touch”, cv.dragCard ) at the moment, so they are very simple.

As mentioned, cv.resetCard is being called inside cv.dragCard which is a touch event function. It’s very standard looking other than that I’ve compartmentalized it into smaller functions, but I will post it below in case it helps:

[lua]

function cv.touchBegan( event, target )

    – Force target to be top-most and maintain focus. How does parent work exactly?

    local parent = target.parent

    parent:insert( target )

    display.getCurrentStage():setFocus( target )

    target.isFocus = true

    – Storing original coordinates.

    target.xO = target.x

    target.yO = target.y

    – Storing original coordinates relative to touch.

    target.xD = event.x - target.x

    target.yD = event.y - target.y

end

function cv.touchMoved( event, target )

    – Move object relative to touch.

    target.x = event.x - target.xD

    target.y = event.y - target.yD

end

function cv.touchEnded( target )

    cv.resetCard( target, true )

end

function cv.touchCancelled( target )

    cv.resetCard( target, true )

end

– Function to handle player touching cards in hand.

function cv.dragCard( event )

    local target = event.target

    if event.phase == “began” then cv.touchBegan( event, target )

    elseif target.isFocus then

        if event.phase == “moved” then cv.touchMoved( event, target )

        elseif event.phase == “ended” then cv.touchEnded( target )

        elseif event.phase == “cancelled” then cv.touchCancelled( target )

        else end

    else end

    return true

end

[/lua]

Consult the documentation here: http://docs.coronalabs.com/api/library/timer/performWithDelay.html. Since you’re passing a parameter to the function you want to call with a delay, you need to wrap it in a Lua closure. - Andrew

To make it simple for you, I’ll give you an example. You are having problems with this function call:

timer.performWithDelay( 100, cv.addListener( target ) )

You cannot put a parameter directly into a delayed/oncomplete function call, so you can do one of these 2 things.

Either create an anonymous function on the fly:

timer.performWithDelay( 100, function() cv.addListener( target ) end )

Or create a temporary function just before the performWithDelay call:

local function myClosure() cv.addListener( target ) end timer.performWithDelay( 100, myClosure() )

Personally I usually use the first option, but there may be performance issues depending on what exactly you need to do.

@aukStudios and AlanPlantPot

Thank you two very much! I’m sure there’s a reason for that restriction but it’s awfully inconvenient. At least I get how it works now, so thank you.

Consult the documentation here: http://docs.coronalabs.com/api/library/timer/performWithDelay.html. Since you’re passing a parameter to the function you want to call with a delay, you need to wrap it in a Lua closure. - Andrew

To make it simple for you, I’ll give you an example. You are having problems with this function call:

timer.performWithDelay( 100, cv.addListener( target ) )

You cannot put a parameter directly into a delayed/oncomplete function call, so you can do one of these 2 things.

Either create an anonymous function on the fly:

timer.performWithDelay( 100, function() cv.addListener( target ) end )

Or create a temporary function just before the performWithDelay call:

local function myClosure() cv.addListener( target ) end timer.performWithDelay( 100, myClosure() )

Personally I usually use the first option, but there may be performance issues depending on what exactly you need to do.

@aukStudios and AlanPlantPot

Thank you two very much! I’m sure there’s a reason for that restriction but it’s awfully inconvenient. At least I get how it works now, so thank you.