Problems with drag/drop

I am running into two problems with my drag / drop code.

I am moving puzzle pieces on the screen, and I have a function movePiece(event) that is used to listen to touch event.

local function movePiece(event)  
  
 -- @TODO attempt to perform arithmetic on field 'markedX' (a nil value)  
 if event.phase == "began" then  
 -- bring piece to front   
 event.target:toFront()  
  
 --lock focus  
 display.getCurrentStage():setFocus(event.target)  
 event.target.hasFocus = true;  
  
 event.target.markedX = event.target.x -- store x location of object  
 event.target.markedY = event.target.y -- store y location of object  
  
 elseif event.phase == "moved" then  
 local x = (event.x - event.xStart) + event.target.markedX  
 local y = (event.y - event.yStart) + event.target.markedY  
  
 event.target.x, event.target.y = x, y -- move object based on calculations above  

This code works, I do have one problem that crops up every so often that throws errors in the console but does not affect execution of the app.

First issue, I initially tried to create a markedX & markedY and assign event.target.(x/y). But it kept saying markedX was nil. If I changed it to event.target.markedX it works fine. Why can’t I create a local variable and assign event.target.x/y directly to that rather than having to add it to the event object?

2nd question, I occasionally get an error in the console:

attempt to perform arithmetic on field 'markedX' (a nil value)

It seems only to affect the X value, not the Y value, and it only happens once and a while.

[import]uid: 160288 topic_id: 33201 reply_id: 333201[/import]

Touch the screen outside the object, then slide onto it: you won’t get a ‘begin’ event but you will get a ‘moved’ event and markedX will be nil.

For the markedX scoping, declare local markedX before the “begin” if statement, then it is seen in the “moved” if scope. But, attaching it to the target is fine.

[lua]local function movePiece(event)

@TODO attempt to perform arithmetic on field ‘markedX’ (a nil value)
if event.phase == “began” then
– bring piece to front
event.target:toFront()

–lock focus
display.getCurrentStage():setFocus(event.target)
event.target.hasFocus = true;

event.target.markedX = event.target.x – store x location of object
event.target.markedY = event.target.y – store y location of object

elseif event.phase == “moved” and event.target.hasFocus then
local x = (event.x - event.xStart) + event.target.markedX
local y = (event.y - event.yStart) + event.target.markedY

event.target.x, event.target.y = x, y – move object based on calculations above

elseif event.phase==“ended” then
event.target.hasFocus = false
display.getCurrentStage():setFocus(nil)
end[/lua]

(code not tested)
[import]uid: 36578 topic_id: 33201 reply_id: 131905[/import]

I would be tempted to create the 2 extra fields (markedX/Y) when I create the object. You can just set them to zero, thats how I have always done it and you have no worries about if they are created or not.

Dave [import]uid: 117617 topic_id: 33201 reply_id: 131911[/import]

Mate, I don’t see any difference in your code sample to mine, outside of the ended phase (which I have in my complete code file).

If I forward delcare markedX & markedY at the top of my file, it seems to work fine.
I tried declaring at the start of the function, but before the began event, but that did not work.

Neither does it fix the issue of the lack of a began event.

Is there a way in corona to say + markX (if not nil) if nil, don’t + markX without doing a if comparison first? [import]uid: 160288 topic_id: 33201 reply_id: 131913[/import]

This line is different:

[lua]elseif event.phase == “moved” and event.target.hasFocus then[/lua]

You’re right, targetX/targetY should be declared at the top of the file. But, I’d still keep it as event.target.markX, because it belongs to that target. What if you had a bunch of targets in the same file?

[import]uid: 36578 topic_id: 33201 reply_id: 131914[/import]

Nice! I didn’t think of that and I believe that solves the problem I had with it moving off screen and the error.

When I define markX/Y at the top of the file, everything seems to work great. I do have multiple objects, I have 7 pieces each using that same event. But some how it works fine when forward declaring markx/y at the top of the file and referencing it shared in the function.

I believe this is because (with your code change) began is guaranteed to be called prior to move, so markx/y is freshly set. If I had multi-touch enabled this would be a problem though.

The reason I wanted to declare it is to use “local” scope rather than global.

I have a pieces object that is local to the file, I create piece objects for each piece. These piece objects are what are handled by this event handler. I thought it would be more efficient if I used “local” declaration earlier rather than just using event.target.markedX on the fly which I assumed would be global? [import]uid: 160288 topic_id: 33201 reply_id: 131915[/import]

Take a look here: http://developer.coronalabs.com/code/copypaste-touch-function

Maybe that will help. [import]uid: 8271 topic_id: 33201 reply_id: 131926[/import]

I’d like to see your code with the markedX, Y not working. My gut is a scope issue. [import]uid: 19626 topic_id: 33201 reply_id: 131934[/import]

@Mate, thanks a lot. That completely solved my problem and I didn’t think to lock the move event to focus as well. It runs a ton better now and two of the oddness I was experiencing some of the time.

@Rob This is something like what I was doing:

local function movePiece(event)  
   
 local markedX  
 local markedY  
  
 if event.phase == "began" then  
 -- bring piece to front   
 event.target:toFront()  
   
 --lock focus  
 display.getCurrentStage():setFocus(event.target)  
 event.target.hasFocus = true;  
  
 markedX = event.target.x -- store x location of object  
 markedY = event.target.y -- store y location of object  
  
 elseif event.phase == "moved" then  
 local x = (event.x - event.xStart) + markedX  
 local y = (event.y - event.yStart) + markedY  
  
 event.target.x, event.target.y = x, y -- move object based on calculations above  
   
 elseif event.phase=="ended" then  
 event.target.hasFocus = false  
 display.getCurrentStage():setFocus(nil)  
 end  

I also tried putting the local markedX/Y at the beginning of the begin phase. I did not know at the time you can have a move event without a began so I assumed x/y would always be initialized. I didn’t think of the scenario Mate mentioned about dragging the screen and sliding into a piece. I am not quite sure how this works though, but forcing the move event to also have focus before my code executes, makes everything work perfectly. [import]uid: 160288 topic_id: 33201 reply_id: 131962[/import]

Thanks Horacebury, I am going to have a look shortly. [import]uid: 160288 topic_id: 33201 reply_id: 131963[/import]

Touch the screen outside the object, then slide onto it: you won’t get a ‘begin’ event but you will get a ‘moved’ event and markedX will be nil.

For the markedX scoping, declare local markedX before the “begin” if statement, then it is seen in the “moved” if scope. But, attaching it to the target is fine.

[lua]local function movePiece(event)

@TODO attempt to perform arithmetic on field ‘markedX’ (a nil value)
if event.phase == “began” then
– bring piece to front
event.target:toFront()

–lock focus
display.getCurrentStage():setFocus(event.target)
event.target.hasFocus = true;

event.target.markedX = event.target.x – store x location of object
event.target.markedY = event.target.y – store y location of object

elseif event.phase == “moved” and event.target.hasFocus then
local x = (event.x - event.xStart) + event.target.markedX
local y = (event.y - event.yStart) + event.target.markedY

event.target.x, event.target.y = x, y – move object based on calculations above

elseif event.phase==“ended” then
event.target.hasFocus = false
display.getCurrentStage():setFocus(nil)
end[/lua]

(code not tested)
[import]uid: 36578 topic_id: 33201 reply_id: 131905[/import]

I would be tempted to create the 2 extra fields (markedX/Y) when I create the object. You can just set them to zero, thats how I have always done it and you have no worries about if they are created or not.

Dave [import]uid: 117617 topic_id: 33201 reply_id: 131911[/import]

Mate, I don’t see any difference in your code sample to mine, outside of the ended phase (which I have in my complete code file).

If I forward delcare markedX & markedY at the top of my file, it seems to work fine.
I tried declaring at the start of the function, but before the began event, but that did not work.

Neither does it fix the issue of the lack of a began event.

Is there a way in corona to say + markX (if not nil) if nil, don’t + markX without doing a if comparison first? [import]uid: 160288 topic_id: 33201 reply_id: 131913[/import]

This line is different:

[lua]elseif event.phase == “moved” and event.target.hasFocus then[/lua]

You’re right, targetX/targetY should be declared at the top of the file. But, I’d still keep it as event.target.markX, because it belongs to that target. What if you had a bunch of targets in the same file?

[import]uid: 36578 topic_id: 33201 reply_id: 131914[/import]

Nice! I didn’t think of that and I believe that solves the problem I had with it moving off screen and the error.

When I define markX/Y at the top of the file, everything seems to work great. I do have multiple objects, I have 7 pieces each using that same event. But some how it works fine when forward declaring markx/y at the top of the file and referencing it shared in the function.

I believe this is because (with your code change) began is guaranteed to be called prior to move, so markx/y is freshly set. If I had multi-touch enabled this would be a problem though.

The reason I wanted to declare it is to use “local” scope rather than global.

I have a pieces object that is local to the file, I create piece objects for each piece. These piece objects are what are handled by this event handler. I thought it would be more efficient if I used “local” declaration earlier rather than just using event.target.markedX on the fly which I assumed would be global? [import]uid: 160288 topic_id: 33201 reply_id: 131915[/import]

Horacebury,

I looked through your code and I had a few questions.

Is touchBegan, touchMoved, touchEnded your own functions that you attached to the object?

Do you have a simple example of this?

What is the purpose of returning true/false?

I love the idea of this, where you don’t have to modify it, and just do the callbacks, I am just not sure how to attach the callbacks. I assume you create a these functions, then do something like object.touchBegan = touchBegan to point to the function?
[import]uid: 160288 topic_id: 33201 reply_id: 132023[/import]

Take a look here: http://developer.coronalabs.com/code/copypaste-touch-function

Maybe that will help. [import]uid: 8271 topic_id: 33201 reply_id: 131926[/import]

Return true or fale indicates to Corona that the event should fall through (false) to the display object below, or not (true.)

Yes, those functions need to be defined on the object you are attaching the event listener to. They would be attached either like this:

[lua]dragTab.touchEnded = function(e)[/lua]

or like this:

[lua]function dragTab:touchEnded(e)[/lua]
[import]uid: 8271 topic_id: 33201 reply_id: 132032[/import]

Very nice how you can use this as a snippet without having to modify it.

I still don’t quite understand the true/false, and I couldn’t see it in the documentation.

Can you explain the scenario where the final return false would occur.
In my code I am not returning true or false, what is happening differently from you returning true?
[import]uid: 160288 topic_id: 33201 reply_id: 132034[/import]

If there’s another listener underneath the initial listener, then it will also receive the touch event, unless you return true from the initial listener.

Not returning anything is equivalent to false - it lets the event pass through. [import]uid: 36578 topic_id: 33201 reply_id: 132036[/import]