making coin patterns

Hi.

I’m trying to create coin patterns to use in my game, I can generate a coin randomly on the screen and apply physics to it no problem however to create a group I’ve created a pattern table which holds x and y coords in it for the different coins which build up that pattern. This does work as in I get the pattern of coins but I can’t seem to apply physics to the individual coins.

I have a createcoin function which takes the x and y coord of a coin and has a local coin declaration and I set the physics in this function then add the coin to a coin group. This createcoin function is called multiple times by a createcoingroup function which randomly chooses one of the entries in the pattern table.

Are the physics failing due to some kind of scope issue seen as every coin is linked to a local coin call??

What is the best way of doing something like this??

Thanks

It depends on how you are spawning your coins. Are you declaring physics bodies upon spawn? If you post your spawn code that would be helpful.

local coinPatterns={ line={{x=0,y=0},{x=25,y=0},{x=50,y=0}} } -- Create Individual Coin local function createCoin(x,y) local coin=display.newImageRect("images/coin.png",20,20) coin.anchorX,coin.anchorY=0,0 coin.y=y coin.x=x coin.id='coin' physics.addBody(coin,'static',{isSensor=true,radius=10}) return coin end -- Create a coin group local function createCoinGroup() local coinGroup=display.newGroup() for key,value in pairs(coinPatterns.line) do local coin=createCoin(value.x,value.y) coinGroup:insert(coin) end coinGroup.x=screenW coinGroup.y=50 transition.to(coinGroup,{time=2000,x=0-coinGroup.width,onComplete=function() coinGroup:removeSelf() coinGroup=nil end}) foregroundGroup:insert(coinGroup) end createCoinGroup()

Above is a snippet of the code i’m using - just looking at it now I can see there has to be a problem with scope with the local coin in both functions I just can’t work it out.

The coins are created successfully and in debug mode look like they have a physics object around them, but in my on collision function I can’t pick up individual coins.

Thanks

Well, we’ve got a few things here.

First, you don’t appear to be setting any variables to identify your coins when they are spawned. The variable you have here:

coin.id = "coin"

Gives the id of “coin” to every object, but that isn’t very individual. Depending on your collision listener, it might not be best practice. In addition, creating objects in this way, while technically feasible, doesn’t give much control over them. Creating them as objects in a table would give you better control over their individual interactions.

Second, and I’m just hypothesizing because I don’t know what your collision listener looks like, when you’re inserting your coins into a display group, and then inserting that display group into another display group, it can be hard to remember which objects are in which group. If you have objects that are outside of the given display group and display groups are over-written, you might not see objects collide in the right way.

Third, and again, this is a hypothesis, if you’re not using physics to have objects collide with each other, you won’t see any collisions happen. Seems obvious, but if you use transition.to instead of body.applyForce (or similar), you aren’t going to get the same results.

Here’s a quick snippet of how I build a tiled background for testing purposes:

local backg = {} local moveY = 10 local moveX = 20 local cellWidth = 34 local cellHeight = 34 local gridGroup = display.newGroup() local function buildBack1() for x = 1, 20 do backg[x] = {} for y = 1, 5 do backg[x][y] = display.newRect(0, 0, cellWidth, cellHeight) backg[x][y].x = x\*cellWidth+moveY backg[x][y].y = y\*cellHeight+moveX backg[x][y].id = ("backg["..x.."]["..y.."]") backg[x][y]:setFillColor(1, 0, 0) gridGroup:insert(backg[x][y]) end end end buildBack1()

Notice how the tiles are display objects, and also part of a table. This way, I can reference them as individual tiles, or as a large group, later on.

Is there a way you could post your collision code so we can confirm how and what is supposed to be interacting with what?

The only thing I want to do with a coin is to increment a counter and to make that particular object disapeer.

I dont really need anything else regarding the coin so i dont mind that I dont have full control over it, the only reason I have id=coin is so that in my collision listener I can say if object1.id==‘character’ and object.id==‘coin’ then… thats when I increment counter and remove coin.

Do I need to do it the way you have in order to do this or is that only to have full control over other things??

No, you don’t need to mimic my method exactly. However, since your method wasn’t working, I figured I’d throw out another method, in case that helped you with optimizing your own code.

It sounds like your spawning is working the way you wanted, without any modification. Do you have print statements for each phase of collision? Are you confirming that the coins are being moved by physics and not transitions? Are you sure you want your coins to be static and not dynamic? Here are some tips from CL’s Brent S on physics body interaction:

  1. a collision will only occur between a dynamic body and another type of body (or another dynamic one). Never between two non-dynamic bodies. This is a rule regardless of anything else including awake state, collision filters, etc.

  2. if two bodies (sensors) are already overlapping, and one (or both) go to sleep, you can usually re-trigger a collision detection by force-waking it up and then setting “.isBodyActive” to true. This should “flash” the body’s sensory state and send back a collision response. You might, however, need to set “.isBodyActive” to false, then to true, in two consecutive lines… a little testing will be required to see which works.

Best regards,
Brent

If you want to post your collision code, we can take a closer look.

Hi, 

My collision code is quite basic for the coins. My ‘character’ is a dynamic physics object and my coins are static and have isSensor although I havent put the allow sleep command on them.

-- when a collision occurs local function onCollision(event) if (event.phase=='began') then if event.object1.id=='coin' or event.object2.id=='coin' then if mydata.audio==true then audio.play(coinAudio) end mydata.coins=mydata.coins+1 if (event.object1.id=='coin') then transition.to(event.object1,{time=50,alpha=0}) else transition.to(event.object2,{time=50,alpha=0}) end end end end 

Hope this helps anyways - thats pretty much all the code now i’ve used to create the coins and physics for them.

Thanks for your help

Kevin

I cleaned it up a bit:

local function onCollision(event) if (event.phase=='began') then if event.object1.id=='coin' then if mydata.audio==true then audio.play(coinAudio) end mydata.coins=mydata.coins+1 transition.to(event.object1,{time=50,alpha=0}) end end end 

I’m presuming, though, that you are getting an error when the coin object is supposed to transition, as box2D cannot affect any objects that are in an unresolved physics state. Are you seeing any message in the terminal to that affect? I’d suggest using the below, with the print statements, to see if the collision is working. I’m assuming the listener code, but I’ll put that in below:

local function onCollision(event) if (event.phase=='began') then if event.object1.id=='coin' then print("MY CHARACTER HAS COLLIDED WITH A COIN!") end end end character:addEventListener("collision", onCollision)

Firstly how do you know event.object1 is the coin and not event.object2… whats the difference?

With regards to coin detection, i find it to be very strange, I created a lot of these patterns to be scattered throughout the level, and hitting any of them came up with nothing in the collision detection… about 20/30 seconds in to the level all of sudden the detection started to work however in a very strange way as in sometimes it worked and sometimes it didn’t, and if I hit coin1 of pattern 1 then coin1 of pattern 2 would also disappear.

I’m thinking how i’m apply the physics doesn’t work. 

When the coins did detect correctly the alpha did work on them

One more thing… I actually have the collision set on Runtime:addEventListener(‘collision’,onCollision)…

Could this be causing the issue???

The local collision makes sense now so i’ve changed to that instead of Runtime collision, unfortunately it has had no effect on the coins, ive moved them down so my character literally walks through them - absolutely nothing until around 20/30 seconds in to the game, then a few work / few dont - very odd

its event.other.id btw instead of event.object1.id - that seems to be one of the Runtime vs Local things

At this point, you should start simple and then make it more complicated. So, just start by creating one coin and setting it near the character and have it collide. If it’s that works, then you start adding back in more complicated code. Everything you’re doing seems to be fine, so starting small and then getting larger is the best way to tackle this one.

If you look at my earlier code where I run createCoinGroup()…

If i ignore that and just run createCoin() instead, this creates just a single coin on its own… this does work exactly how expected.

its only when I put them in the group the physics seem to play up, even though in debug they do still have a physics square around each one.

It depends on how you are spawning your coins. Are you declaring physics bodies upon spawn? If you post your spawn code that would be helpful.

local coinPatterns={ line={{x=0,y=0},{x=25,y=0},{x=50,y=0}} } -- Create Individual Coin local function createCoin(x,y) local coin=display.newImageRect("images/coin.png",20,20) coin.anchorX,coin.anchorY=0,0 coin.y=y coin.x=x coin.id='coin' physics.addBody(coin,'static',{isSensor=true,radius=10}) return coin end -- Create a coin group local function createCoinGroup() local coinGroup=display.newGroup() for key,value in pairs(coinPatterns.line) do local coin=createCoin(value.x,value.y) coinGroup:insert(coin) end coinGroup.x=screenW coinGroup.y=50 transition.to(coinGroup,{time=2000,x=0-coinGroup.width,onComplete=function() coinGroup:removeSelf() coinGroup=nil end}) foregroundGroup:insert(coinGroup) end createCoinGroup()

Above is a snippet of the code i’m using - just looking at it now I can see there has to be a problem with scope with the local coin in both functions I just can’t work it out.

The coins are created successfully and in debug mode look like they have a physics object around them, but in my on collision function I can’t pick up individual coins.

Thanks

Well, we’ve got a few things here.

First, you don’t appear to be setting any variables to identify your coins when they are spawned. The variable you have here:

coin.id = "coin"

Gives the id of “coin” to every object, but that isn’t very individual. Depending on your collision listener, it might not be best practice. In addition, creating objects in this way, while technically feasible, doesn’t give much control over them. Creating them as objects in a table would give you better control over their individual interactions.

Second, and I’m just hypothesizing because I don’t know what your collision listener looks like, when you’re inserting your coins into a display group, and then inserting that display group into another display group, it can be hard to remember which objects are in which group. If you have objects that are outside of the given display group and display groups are over-written, you might not see objects collide in the right way.

Third, and again, this is a hypothesis, if you’re not using physics to have objects collide with each other, you won’t see any collisions happen. Seems obvious, but if you use transition.to instead of body.applyForce (or similar), you aren’t going to get the same results.

Here’s a quick snippet of how I build a tiled background for testing purposes:

local backg = {} local moveY = 10 local moveX = 20 local cellWidth = 34 local cellHeight = 34 local gridGroup = display.newGroup() local function buildBack1() for x = 1, 20 do backg[x] = {} for y = 1, 5 do backg[x][y] = display.newRect(0, 0, cellWidth, cellHeight) backg[x][y].x = x\*cellWidth+moveY backg[x][y].y = y\*cellHeight+moveX backg[x][y].id = ("backg["..x.."]["..y.."]") backg[x][y]:setFillColor(1, 0, 0) gridGroup:insert(backg[x][y]) end end end buildBack1()

Notice how the tiles are display objects, and also part of a table. This way, I can reference them as individual tiles, or as a large group, later on.

Is there a way you could post your collision code so we can confirm how and what is supposed to be interacting with what?

The only thing I want to do with a coin is to increment a counter and to make that particular object disapeer.

I dont really need anything else regarding the coin so i dont mind that I dont have full control over it, the only reason I have id=coin is so that in my collision listener I can say if object1.id==‘character’ and object.id==‘coin’ then… thats when I increment counter and remove coin.

Do I need to do it the way you have in order to do this or is that only to have full control over other things??

No, you don’t need to mimic my method exactly. However, since your method wasn’t working, I figured I’d throw out another method, in case that helped you with optimizing your own code.

It sounds like your spawning is working the way you wanted, without any modification. Do you have print statements for each phase of collision? Are you confirming that the coins are being moved by physics and not transitions? Are you sure you want your coins to be static and not dynamic? Here are some tips from CL’s Brent S on physics body interaction:

  1. a collision will only occur between a dynamic body and another type of body (or another dynamic one). Never between two non-dynamic bodies. This is a rule regardless of anything else including awake state, collision filters, etc.

  2. if two bodies (sensors) are already overlapping, and one (or both) go to sleep, you can usually re-trigger a collision detection by force-waking it up and then setting “.isBodyActive” to true. This should “flash” the body’s sensory state and send back a collision response. You might, however, need to set “.isBodyActive” to false, then to true, in two consecutive lines… a little testing will be required to see which works.

Best regards,
Brent

If you want to post your collision code, we can take a closer look.

Hi, 

My collision code is quite basic for the coins. My ‘character’ is a dynamic physics object and my coins are static and have isSensor although I havent put the allow sleep command on them.

-- when a collision occurs local function onCollision(event) if (event.phase=='began') then if event.object1.id=='coin' or event.object2.id=='coin' then if mydata.audio==true then audio.play(coinAudio) end mydata.coins=mydata.coins+1 if (event.object1.id=='coin') then transition.to(event.object1,{time=50,alpha=0}) else transition.to(event.object2,{time=50,alpha=0}) end end end end 

Hope this helps anyways - thats pretty much all the code now i’ve used to create the coins and physics for them.

Thanks for your help

Kevin

I cleaned it up a bit:

local function onCollision(event) if (event.phase=='began') then if event.object1.id=='coin' then if mydata.audio==true then audio.play(coinAudio) end mydata.coins=mydata.coins+1 transition.to(event.object1,{time=50,alpha=0}) end end end 

I’m presuming, though, that you are getting an error when the coin object is supposed to transition, as box2D cannot affect any objects that are in an unresolved physics state. Are you seeing any message in the terminal to that affect? I’d suggest using the below, with the print statements, to see if the collision is working. I’m assuming the listener code, but I’ll put that in below:

local function onCollision(event) if (event.phase=='began') then if event.object1.id=='coin' then print("MY CHARACTER HAS COLLIDED WITH A COIN!") end end end character:addEventListener("collision", onCollision)