Overlapping object code - What is wrong?

Hi guys,

I’m trying to prevent spawning circles from overlapping. This is my code:

 for i=1, math.random(1, 6) do radius = math.random(centerX \* 0.05, centerX \* 0.2) obstacles[i] = display.newCircle(centerX, centerY, radius) obstacles[i].x = math.random((centerX \* 0.1) + (radius), actualW - ((centerX \* 0.1) + (radius))) obstacles[i].y = math.random(centerY \* 0.425, actualH - centerY \* 0.25) obstacles[i].radius = radius local randomColor = math.random(1,2) if randomColor == 1 then obstacles[i]:setFillColor(26/255, 188/255, 156/255) else obstacles[i]:setFillColor(243/255, 156/255, 18/255) end obstacles[i].strokeWidth = radius \* 0.2 for j=1, #obstacles - 1 do if obstacles[i].x - obstacles[i].radius \<= obstacles[j].x and obstacles[i].x + obstacles[i].radius \>= obstacles[j].x then if obstacles[i].y - obstacles[i].radius \<= obstacles[j].y and obstacles[i].y + obstacles[i].radius \>= obstacles[j].y then i = i - 1 end end end end

So what I’m trying to do is loop through all the objects in the list and check their x and y positions. If the new object (obstacles[j]) is in between them, I decrement i by 1 so my for loop would do the loop over again and overwrite the current circle. This isn’t working for me for some reason. Does anyone see what’s wrong?

I haven’t run your code, but the logic of decrementing the loop counter seems heavy to me. Why not just check that a location of a circle is overlapping and simply recreate it somewhere else? You’re already randomising the size and location of the circles, so just check if the circle will overlap and don’t do it if it will. Here’s what I would do (this has been run):

local function distance( ax, ay, bx, by ) local width, height = bx-ax, by-ay return (width\*width + height\*height) ^ 0.5 end local function isOverlapping( parent, x, y, radius ) for i=1, parent.numChildren do local circle = parent[i] if (distance( x, y, circle.x, circle.y ) \<= radius+circle.radius) then return true end end return false end local function newCircle( parent, minradius, maxradius ) while (true) do local r = math.random( minradius, maxradius ) local x, y = math.random( r, display.actualContentWidth-r ), math.random( r, display.actualContentHeight-r ) if (not isOverlapping( parent, x, y, r )) then local circle = display.newCircle( parent, x, y, r ) circle.radius = r return circle end end end local function newCircles( parent, count, minradius, maxradius ) for i=1, count do newCircle( parent, minradius, maxradius ) end end local group = display.newGroup() newCircles( group, 10, 50, 200 )

In my opinion you check in two if statements if center of one circle is inside other one but  this don’t guarantee that cirlces don’t ovelap. To ensure circles don’t overlap you can check if distance of centers of two circles is greater than sum of their radii.

I did something like that

local rand = math.random local sqrt = math.sqrt local actualW = display.contentWidth local actualH = display.contentHeight local centerX = display.contentCenterX local centerY = display.contentCenterY local obstacles = {} local radius, x, y, j for i=1, 7 do -- rand(1, 6) do repeat -- Parameters for new circle &nbsp; &nbsp;&nbsp; radius = rand(centerX \* 0.05, centerX \* 0.2) &nbsp; &nbsp;&nbsp; x = rand((centerX \* 0.1) + (radius), actualW - ((centerX \* 0.1) + (radius))) &nbsp; &nbsp;&nbsp; y = rand(centerY \* 0.425, actualH - centerY \* 0.25) &nbsp; &nbsp;&nbsp; j = 1 &nbsp; &nbsp;&nbsp; if #obstacles \> 0 then &nbsp; &nbsp;&nbsp; -- Check if any circles overlap if not when j = #obstacles + 1 &nbsp; &nbsp; while #obstacles \>= j and sqrt((obstacles[j].x - x)^2 + (obstacles[j].y - y)^2) \> radius \* 0.4 + radius + obstacles[j].radius do &nbsp; &nbsp; j = j + 1 &nbsp; &nbsp; end &nbsp; &nbsp;&nbsp; end until not ( #obstacles \>= j and #obstacles \> 0 ) &nbsp; &nbsp; obstacles[i] = display.newCircle(x, y, radius) &nbsp; &nbsp; obstacles[i].radius = radius &nbsp; &nbsp; local randomColor = math.random(1,2) &nbsp; &nbsp; if randomColor == 1 then &nbsp; &nbsp; &nbsp; &nbsp; obstacles[i]:setFillColor(26/255, 188/255, 156/255) &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; obstacles[i]:setFillColor(243/255, 156/255, 18/255) &nbsp; &nbsp; end &nbsp; &nbsp; obstacles[i].strokeWidth = radius \* 0.2 end

May be you be interesed in this post how-to-prevent-a-spawned-object-from-overlapping-xy-coordinates-with-a-previous-iteration-of-the-same-object

I haven’t run your code, but the logic of decrementing the loop counter seems heavy to me. Why not just check that a location of a circle is overlapping and simply recreate it somewhere else? You’re already randomising the size and location of the circles, so just check if the circle will overlap and don’t do it if it will. Here’s what I would do (this has been run):

local function distance( ax, ay, bx, by ) local width, height = bx-ax, by-ay return (width\*width + height\*height) ^ 0.5 end local function isOverlapping( parent, x, y, radius ) for i=1, parent.numChildren do local circle = parent[i] if (distance( x, y, circle.x, circle.y ) \<= radius+circle.radius) then return true end end return false end local function newCircle( parent, minradius, maxradius ) while (true) do local r = math.random( minradius, maxradius ) local x, y = math.random( r, display.actualContentWidth-r ), math.random( r, display.actualContentHeight-r ) if (not isOverlapping( parent, x, y, r )) then local circle = display.newCircle( parent, x, y, r ) circle.radius = r return circle end end end local function newCircles( parent, count, minradius, maxradius ) for i=1, count do newCircle( parent, minradius, maxradius ) end end local group = display.newGroup() newCircles( group, 10, 50, 200 )

In my opinion you check in two if statements if center of one circle is inside other one but  this don’t guarantee that cirlces don’t ovelap. To ensure circles don’t overlap you can check if distance of centers of two circles is greater than sum of their radii.

I did something like that

local rand = math.random local sqrt = math.sqrt local actualW = display.contentWidth local actualH = display.contentHeight local centerX = display.contentCenterX local centerY = display.contentCenterY local obstacles = {} local radius, x, y, j for i=1, 7 do -- rand(1, 6) do repeat -- Parameters for new circle &nbsp; &nbsp;&nbsp; radius = rand(centerX \* 0.05, centerX \* 0.2) &nbsp; &nbsp;&nbsp; x = rand((centerX \* 0.1) + (radius), actualW - ((centerX \* 0.1) + (radius))) &nbsp; &nbsp;&nbsp; y = rand(centerY \* 0.425, actualH - centerY \* 0.25) &nbsp; &nbsp;&nbsp; j = 1 &nbsp; &nbsp;&nbsp; if #obstacles \> 0 then &nbsp; &nbsp;&nbsp; -- Check if any circles overlap if not when j = #obstacles + 1 &nbsp; &nbsp; while #obstacles \>= j and sqrt((obstacles[j].x - x)^2 + (obstacles[j].y - y)^2) \> radius \* 0.4 + radius + obstacles[j].radius do &nbsp; &nbsp; j = j + 1 &nbsp; &nbsp; end &nbsp; &nbsp;&nbsp; end until not ( #obstacles \>= j and #obstacles \> 0 ) &nbsp; &nbsp; obstacles[i] = display.newCircle(x, y, radius) &nbsp; &nbsp; obstacles[i].radius = radius &nbsp; &nbsp; local randomColor = math.random(1,2) &nbsp; &nbsp; if randomColor == 1 then &nbsp; &nbsp; &nbsp; &nbsp; obstacles[i]:setFillColor(26/255, 188/255, 156/255) &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; obstacles[i]:setFillColor(243/255, 156/255, 18/255) &nbsp; &nbsp; end &nbsp; &nbsp; obstacles[i].strokeWidth = radius \* 0.2 end

May be you be interesed in this post how-to-prevent-a-spawned-object-from-overlapping-xy-coordinates-with-a-previous-iteration-of-the-same-object