Tinkering with physics, just a quick question.

I made a simple “Angry Birds” type physics “game” (if you want to call it that) for practice. It’s really basic, just creates a circle and a stack of crates. The circle is pulled back and launched to knock the crates down. I wanna be able to make the crates “drag and drop”, so that I could stack them up again without restarting the game.

Here’s what I got:

– Time to throw in the crates.

for i = 0, 10 do

local crate = display.newImageRect(“images/crate2.png”, 25, 25)

crate.anchorX = 0.0

crate.x = display.contentCenterX + 50

crate.y = (display.contentCenterY - 100) + 10*i

physics.addBody(crate, “dynamic”, {density = 1.0, friction = 0.3, bounce= 0.0, isSensor = false})

end

function circleTouched(event)

    if event.phase == “began” then

display.getCurrentStage():setFocus(circle)

elseif event.phase == “ended” then

   circle:applyLinearImpulse(((event.xStart - event.x) / 4), ((event.yStart - event.y) / 4), circle.x, circle.y)

display.getCurrentStage():setFocus(nil)

end

end

function crateTouched(event)

    if event.phase == “began” then

self.markX = self.x

self.markY = self.y

elseif event.phase == “moved” then

local x = (event.x - event.xStart) + self.markX

local y = (event.y - event.yStart) + self.markY

end

return true

end

– Add event listener

circle:addEventListener(“touch”, circleTouched)

crate:addEventListener(“touch”, crateTouched)

I’m getting the error on the bottom (where the event listener is) that crate is a nil value. I’d imagine because the crate variable is within the “for” function, and cannot be called anywhere else? If that’s the case, how would I go about fixing this? This is only my third day messing around with Corona, so sorry if I come off as a noob.

Any help would be appreciated.

P.S. If necessary, I will post the entire code…which isn’t very long at all.

I was just thinking that it probably won’t work anyways since this is a physics object. I’m sure there is some other method for working with physics?

You’re spot on. You create crate inside the loop but the variable “crate” only exists inside the for loop.  The object and allocated memory get lost as you go through the loop.  You create them then loose reference to them. 

There are two thing you need to learn:  scope (i.e. defining variables so various part of the code can see them.)  and arrays (tables).  You need to keep track of each object.  When you have a reference to each object you can add touch handlers to them to do your drag and dropping.

Rob

Would this be the proper tutorial to read?

https://coronalabs.com/blog/2011/09/21/tutorial-scopes-for-functions/

After reading through it, I still can’t figure out how to make that variable available from elsewhere in the code. Is there something I’m missing?

My head hurts lol.

Hi nick,

you should be putting all the created crates in a table which is declared above the for loop, so that the scope will be through out the file.

and once all the crates are created you can iterate through all the crates and add the touch event listener to each crate, and then on touch of each crate you will get call back to the touch event listener .

Check the below code:

crateTable = {} for i = 0, 10 do crateTable[i] = display.newImageRect("crate.png", 25, 25) crateTable[i].anchorX = 0.0 crateTable[i].x = display.contentCenterX + 50 crateTable[i].y = (display.contentCenterY - 100) + 10\*i physics.addBody(crateTable[i], "dynamic", {density = 1.0, friction = 0.3, bounce= 0.0, isSensor = false}) end function crateTouched(event) if event.phase == "began" then self.markX = self.x self.markY = self.y elseif event.phase == "moved" then local x = (event.x - event.xStart) + self.markX local y = (event.y - event.yStart) + self.markY end return true end -- Add event listener for i = 0, 10 do crateTable[i]:addEventListener("touch", crateTouched) end

Wow, thanks. I didn’t realize creating tables was that simple.

I appreciate your help. This is gonna help immensely in the long run.

More on lua tables here:

http://www.lua.org/pil/2.5.html

I finally got time to tinker around a bit this morning (I’ve got 4 kids and a wife who is always working…hard to find time for this lol).

I created the crate table, like you explained above, but it gave me this error…I took screenshots of the error and where it took place in the code. What did I do wrong??? =/

Also, what is the purpose of adding the event listener at the bottom into a for loop?

Hey i changed the image path in the line 51 for testing point it to correct image, my bad.

How did I not catch that? Haha.

I’m able to use the table now, but when I click on the crate I get this error [image attached].

Here’s where the error occured:

function crateTouched(event)

if event.phase == “began” then

self.markX = self.x
self.markY = self.y

elseif event.phase == “moved” then

local x = (event.x - event.xStart) + self.markX
local y = (event.y - event.yStart) + self.markY
end

return true
end

– Add event listener
circle:addEventListener(“touch”, circleTouched)

for i = 0, 10 do
crateTable[i]:addEventListener(“touch”, crateTouched)
end

It’s on the line that says “self.markX = self.x”

You are mixing the concept of “table” listeners (which don’t mean because you’re objects are in tables, btw) and function listeners.  All of your code including how you add the event listener and define the function are done as “function listeners” (my preferred way, btw).

Where you’re mixing the concepts is this part of the code:

self.markX = self.x
self.markY = self.y

There is no “self” with function handlers.  Instead event.target represents the object that’s being interacted with.  You can do:

event.target.markX = event.target.x

event.target.markY = event.target.y

instead.

Rob

Thanks =D

Now I’m getting "attempting to perform arithmetics on field “markX” (a nil value)?

Does markX need to be defined somewhere in the code?

I’ll show you what line gave the error:

crateTable = {}

for i = 0, 10 do

crateTable[i] = display.newImageRect(“images/crate2.png”, 25, 25)

crateTable[i].anchorX = 0.0

crateTable[i].x = display.contentCenterX + 50

crateTable[i].y = (display.contentCenterY - 100) + 10*i

physics.addBody(crateTable[i], “dynamic”, {density = 1.0, friction = 0.3, bounce= 0.0, isSensor = false})

end

function circleTouched(event)

    if event.phase == “began” then

display.getCurrentStage():setFocus(circle)

elseif event.phase == “ended” then

   circle:applyLinearImpulse(((event.xStart - event.x) / 4), ((event.yStart - event.y) / 4), circle.x, circle.y)

display.getCurrentStage():setFocus(nil)

end

end

function crateTouched(event)

    if event.phase == “began” then

– The error is just below here on markX (nil value)

event.target.markX = event.target.x

event.target.markY = event.target.y

elseif event.phase == “moved” then

local x = (event.x - event.xStart) + event.target.markX

local y = (event.y - event.yStart) + event.target.markY

end

return true

end

– Add event listener

circle:addEventListener(“touch”, circleTouched)

for i = 0, 10 do

crateTable[i]:addEventListener(“touch”, crateTouched)

end

It’s possible to get a “moved” phase without getting “began” phase.  You define .markX and .markY in the began phase, which should work most of the time.  But it’s always best to initialize these things when you create the object.

Where you do:
 

crateTable[i].x = display.contentCenterX + 50

crateTable[i].y = (display.contentCenterY - 100) + 10*i

add:

crateTable[i].markX = crateTable[i].x

crateTable[i].markY = crateTable[i].y

to record your starting position.

Rob

Thanks.

No error this time but the blocks won’t do anything when I try to drag them.

Is this due to the object having physics properties?

Hi Nick,

There’s no reason physics should be preventing the blocks from moving in this way… well, technically it could but that would be more advanced, like the blocks were welded/joined to some other static object, etc… and I doubt you’ve done anything like that.

Brent

I was just thinking that it probably won’t work anyways since this is a physics object. I’m sure there is some other method for working with physics?

You’re spot on. You create crate inside the loop but the variable “crate” only exists inside the for loop.  The object and allocated memory get lost as you go through the loop.  You create them then loose reference to them. 

There are two thing you need to learn:  scope (i.e. defining variables so various part of the code can see them.)  and arrays (tables).  You need to keep track of each object.  When you have a reference to each object you can add touch handlers to them to do your drag and dropping.

Rob

Would this be the proper tutorial to read?

https://coronalabs.com/blog/2011/09/21/tutorial-scopes-for-functions/

After reading through it, I still can’t figure out how to make that variable available from elsewhere in the code. Is there something I’m missing?

My head hurts lol.

Hi nick,

you should be putting all the created crates in a table which is declared above the for loop, so that the scope will be through out the file.

and once all the crates are created you can iterate through all the crates and add the touch event listener to each crate, and then on touch of each crate you will get call back to the touch event listener .

Check the below code:

crateTable = {} for i = 0, 10 do crateTable[i] = display.newImageRect("crate.png", 25, 25) crateTable[i].anchorX = 0.0 crateTable[i].x = display.contentCenterX + 50 crateTable[i].y = (display.contentCenterY - 100) + 10\*i physics.addBody(crateTable[i], "dynamic", {density = 1.0, friction = 0.3, bounce= 0.0, isSensor = false}) end function crateTouched(event) if event.phase == "began" then self.markX = self.x self.markY = self.y elseif event.phase == "moved" then local x = (event.x - event.xStart) + self.markX local y = (event.y - event.yStart) + self.markY end return true end -- Add event listener for i = 0, 10 do crateTable[i]:addEventListener("touch", crateTouched) end

Wow, thanks. I didn’t realize creating tables was that simple.

I appreciate your help. This is gonna help immensely in the long run.