Create random position that are not colliding each other

Hi.

i have been trying to create a app that has a random positioning of certain objects every time 

the game loads the same level. The problem is, I get stuck at providing the random coordinates

with the objects. Each object sizes are different, and i need to prevent them from ‘stacking’ on 

top of each other.

This is what I get so far:

local gridX = {64, 192, 320, 448, 576, 704, 832, 960} local gridY = {76.8, 230.4, 384, 537.6, 691.2} --loop instantiate holeborder depend on which world local tempX, tempY = {}, {} for i = 1, world do local shapes = tonumber(puzzleCode[i]:sub(4,5)) local colors = tonumber(puzzleCode[i]:sub(1,2)) local levels = tonumber(puzzleCode[i]:sub(7,8)) if world == 1 then print('entering if 1') puzzleCoor[i].x = gridX[math.random(2, 5)] puzzleCoor[i].y = gridY[math.random(1, 3)] else print('entering if else') if levels == 1 then puzzleCoor[i].x = gridX[math.random(2, 5)] puzzleCoor[i].y = gridY[math.random(1, 3)] elseif levels == 2 then puzzleCoor[i].x = gridX[math.random(2, 5)] puzzleCoor[i].y = gridY[math.random(1, 3)] elseif levels == 3 then puzzleCoor[i].x = gridX[math.random(2, 5)] puzzleCoor[i].y = gridY[math.random(1, 3)] elseif levels == 4 then puzzleCoor[i].x = gridX[math.random(1, 6)] puzzleCoor[i].y = gridY[math.random(0, 4)] elseif levels == 5 then puzzleCoor[i].x = gridX[math.random(1, 6)] puzzleCoor[i].y = gridY[math.random(0, 4)] end if tempX[i] ~= 0 and tempY[i] ~= 0 then print('entering loop') for y = 1, #tempX do while math.abs(tempX[y] - puzzleCoor[i].x) \<= gridX[1] do print('shuffle x') if levels == 1 then puzzleCoor[i].x = gridX[math.random(2, 5)] elseif levels == 2 then puzzleCoor[i].x = gridX[math.random(2, 5)] elseif levels == 3 then puzzleCoor[i].x = gridX[math.random(2, 5)] elseif levels == 4 then puzzleCoor[i].x = gridX[math.random(1, 6)] elseif levels == 5 then puzzleCoor[i].x = gridX[math.random(1, 6)] end end end for y = 1, #tempY do while math.abs(tempY[y] - puzzleCoor[i].y) \<= gridY[1] do print('shuffle y') if levels == 1 then puzzleCoor[i].y = gridY[math.random(1, 3)] elseif levels == 2 then puzzleCoor[i].y = gridY[math.random(1, 3)] elseif levels == 3 then puzzleCoor[i].y = gridY[math.random(1, 3)] elseif levels == 4 then puzzleCoor[i].y = gridY[math.random(0, 4)] elseif levels == 5 then puzzleCoor[i].y = gridY[math.random(0, 4)] end end end end tempX[i] = puzzleCoor[i].x tempY[i] = puzzleCoor[i].y print('x', puzzleCoor[i].x, 'y', puzzleCoor[i].y) print('tempX', tempX[i], 'tempY', tempY[i], 'loop', i) end

the reason why I use ‘lines’ is to detect which shape object is being loaded, so that they are not needed to load

out-of-screen, so I random a smaller portion of the table positions

Hi.  Give the code below a shot.  Or download it HERE.

https://www.youtube.com/watch?v=K3ixlmzfgNk&feature=youtu.be&hd=1

You can probably adapt this to what you need.

local mRand = math.random local mSqrt = math.sqrt&nbsp; local mRad = math.rad local mCos = math.cos&nbsp; local mSin = math.sin local function subVec( x0, y0, x1, y1 ) &nbsp; &nbsp; return { x = x1 - x0, y = y1 - y0 } end local function lenVec( vec ) &nbsp; &nbsp; return mSqrt(vec.x \* vec.x + vec.y \* vec.y) end local function len2Vec( vec ) &nbsp; &nbsp; return vec.x \* vec.x + vec.y \* vec.y end local currentObjects = {} local w &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = display.contentWidth local h &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = display.contentHeight local centerX &nbsp; &nbsp; &nbsp; = w/2 local centerY &nbsp; &nbsp; &nbsp; = h/2 local minX &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= 25 local maxX &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= w - minX local minY &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= 25 local maxY &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= h - minX local maxPieces &nbsp; &nbsp; = 50 local objRadius &nbsp; &nbsp; = 20 local offset &nbsp; &nbsp; &nbsp; &nbsp;= 4 local safeRadius &nbsp; &nbsp;= (objRadius + offset) \* 2 local safeRadius2 &nbsp; = safeRadius \* safeRadius local maxIter &nbsp; &nbsp; &nbsp; = 150 local function safelyPlaceCircle() &nbsp; &nbsp; local tx = mRand( minX, maxX ) &nbsp; &nbsp; local ty = mRand( minY, maxY) &nbsp; &nbsp; local iter = 0 &nbsp; &nbsp; local isSafe = false &nbsp; &nbsp; &nbsp; &nbsp; while( isSafe == false ) do &nbsp; &nbsp; &nbsp; &nbsp; iter = iter + 1 &nbsp; &nbsp; &nbsp; &nbsp; if( iter \> maxIter ) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print("Failed Iter Test") &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; &nbsp; isSafe = true &nbsp; &nbsp; &nbsp; &nbsp; for i = 1, #currentObjects do &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local obj = currentObjects[i] &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local vec = subVec( tx, ty, obj.x, obj.y ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local len2 = len2Vec( vec ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if( len2 \< safeRadius2 ) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isSafe = false &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tx = mRand( minX, maxX ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ty = mRand( minY, maxY ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; end &nbsp; &nbsp; local tmp = display.newCircle( tx, ty, objRadius ) &nbsp; &nbsp; currentObjects[#currentObjects+1] = tmp &nbsp; &nbsp; print("Created in iterations ", iter) &nbsp; &nbsp; return tmp end -- Make one randomly placed circle at a time -- for i = 1, maxPieces do &nbsp; &nbsp; local tmp = safelyPlaceCircle() &nbsp; &nbsp; if(tmp) then &nbsp; &nbsp; &nbsp; &nbsp; tmp:setFillColor( mRand(0,100)/100, &nbsp;mRand(0,100)/100, mRand(0,100)/100 ) &nbsp; &nbsp; end end

I would either give each shape a bounding circle or bounding box (depends on your shapes, probably whichever suits you) and check it that way.

Alternatively, you could divide the game space up into areas and have only one shape in each area, making sure it fits completely in that area.

@paulscottrobson

that method would work for same shape object, but what if I want to load different sizes object? dividing it into exact areas will cause ‘bleeding’ for bigger shapes. 

@roaminggamer

thanks for sharing the code. I am reading it right now, but I’m afraid I can’t modify much, since the code seems to be

created for instantiate same shape objects, and i need to randomize different sizes of objects. But I’ll try it first :slight_smile:

It really depends what the shapes are, and how tightly you want to pack them. If your shapes are very arbitrary, you may want a specialist collision detection routine (there’s a thing called the Separating Axis algorithm or something like that ?) which can check arbitrary polygons. If they are fairly regular - squares, pentagons, circles, triangles and so on, a bounding box or circle algorithm will be okay as long as you don’t want them insanely tightly packed.

Bounding box and game space areas would work for different shapes - they just waste a little bit of space for performance gain. So if you used a bounding square on a circle, you would waste the corners.

@paulscottrobson

Nah. I just load different sizes of circles, and the shape are all the same. It is just the different

in sizes that makes me unable to divide screens that fits perfectly for each size.

Easy enough then ; just generate random coordinates and check the distance between the centres is less than the sum of the two radii. Probably an idea to have a retry count just in case it gets too full.

after much tinkering with my code, i have gotten into this

local gridX = {170.65, 511.95, 853.25} local gridY = {192, 576} --loop instantiate holeborder depend on which world local number = {} local numbPos = {1, 2, 3, 4, 5, 6} for i = 1, 6 do number[i] = numbPos[math.random(#numbPos)] print(number[i], 'random number') table.remove(numbPos, table.indexOf(numbPos, number[i])) end for i = 1, world do local shapes = tonumber(puzzleCode[i]:sub(4,5)) local colors = tonumber(puzzleCode[i]:sub(1,2)) local levels = tonumber(puzzleCode[i]:sub(7,8)) local x, y local randomnum = number[math.random(#number)] if randomnum == 1 then x = gridX[1] y = gridY[1] elseif randomnum == 2 then x = gridX[2] y = gridY[1] elseif randomnum == 3 then x = gridX[3] y = gridY[1] elseif randomnum == 4 then x = gridX[1] y = gridY[2] elseif randomnum == 5 then x = gridX[2] y = gridY[2] elseif randomnum == 6 then x = gridX[3] y = gridY[2] end puzzleCoor[i].x = math.random(-30, 40) + x puzzleCoor[i].y = math.random(-40, 40) + y table.remove(number, table.indexOf(number, randomnum)) print('x', puzzleCoor[i].x, 'y', puzzleCoor[i].y)

more or less, the code divide the device resolution into big chunks of area, which later be randomize inside the area, by adding a random number or range inside it. not really smart, but enough to complete what I wanted to :slight_smile:

Hi.  Give the code below a shot.  Or download it HERE.

https://www.youtube.com/watch?v=K3ixlmzfgNk&feature=youtu.be&hd=1

You can probably adapt this to what you need.

local mRand = math.random local mSqrt = math.sqrt&nbsp; local mRad = math.rad local mCos = math.cos&nbsp; local mSin = math.sin local function subVec( x0, y0, x1, y1 ) &nbsp; &nbsp; return { x = x1 - x0, y = y1 - y0 } end local function lenVec( vec ) &nbsp; &nbsp; return mSqrt(vec.x \* vec.x + vec.y \* vec.y) end local function len2Vec( vec ) &nbsp; &nbsp; return vec.x \* vec.x + vec.y \* vec.y end local currentObjects = {} local w &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = display.contentWidth local h &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = display.contentHeight local centerX &nbsp; &nbsp; &nbsp; = w/2 local centerY &nbsp; &nbsp; &nbsp; = h/2 local minX &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= 25 local maxX &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= w - minX local minY &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= 25 local maxY &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= h - minX local maxPieces &nbsp; &nbsp; = 50 local objRadius &nbsp; &nbsp; = 20 local offset &nbsp; &nbsp; &nbsp; &nbsp;= 4 local safeRadius &nbsp; &nbsp;= (objRadius + offset) \* 2 local safeRadius2 &nbsp; = safeRadius \* safeRadius local maxIter &nbsp; &nbsp; &nbsp; = 150 local function safelyPlaceCircle() &nbsp; &nbsp; local tx = mRand( minX, maxX ) &nbsp; &nbsp; local ty = mRand( minY, maxY) &nbsp; &nbsp; local iter = 0 &nbsp; &nbsp; local isSafe = false &nbsp; &nbsp; &nbsp; &nbsp; while( isSafe == false ) do &nbsp; &nbsp; &nbsp; &nbsp; iter = iter + 1 &nbsp; &nbsp; &nbsp; &nbsp; if( iter \> maxIter ) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print("Failed Iter Test") &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; &nbsp; isSafe = true &nbsp; &nbsp; &nbsp; &nbsp; for i = 1, #currentObjects do &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local obj = currentObjects[i] &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local vec = subVec( tx, ty, obj.x, obj.y ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local len2 = len2Vec( vec ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if( len2 \< safeRadius2 ) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isSafe = false &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tx = mRand( minX, maxX ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ty = mRand( minY, maxY ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; end &nbsp; &nbsp; local tmp = display.newCircle( tx, ty, objRadius ) &nbsp; &nbsp; currentObjects[#currentObjects+1] = tmp &nbsp; &nbsp; print("Created in iterations ", iter) &nbsp; &nbsp; return tmp end -- Make one randomly placed circle at a time -- for i = 1, maxPieces do &nbsp; &nbsp; local tmp = safelyPlaceCircle() &nbsp; &nbsp; if(tmp) then &nbsp; &nbsp; &nbsp; &nbsp; tmp:setFillColor( mRand(0,100)/100, &nbsp;mRand(0,100)/100, mRand(0,100)/100 ) &nbsp; &nbsp; end end

I would either give each shape a bounding circle or bounding box (depends on your shapes, probably whichever suits you) and check it that way.

Alternatively, you could divide the game space up into areas and have only one shape in each area, making sure it fits completely in that area.

@paulscottrobson

that method would work for same shape object, but what if I want to load different sizes object? dividing it into exact areas will cause ‘bleeding’ for bigger shapes. 

@roaminggamer

thanks for sharing the code. I am reading it right now, but I’m afraid I can’t modify much, since the code seems to be

created for instantiate same shape objects, and i need to randomize different sizes of objects. But I’ll try it first :slight_smile:

It really depends what the shapes are, and how tightly you want to pack them. If your shapes are very arbitrary, you may want a specialist collision detection routine (there’s a thing called the Separating Axis algorithm or something like that ?) which can check arbitrary polygons. If they are fairly regular - squares, pentagons, circles, triangles and so on, a bounding box or circle algorithm will be okay as long as you don’t want them insanely tightly packed.

Bounding box and game space areas would work for different shapes - they just waste a little bit of space for performance gain. So if you used a bounding square on a circle, you would waste the corners.

@paulscottrobson

Nah. I just load different sizes of circles, and the shape are all the same. It is just the different

in sizes that makes me unable to divide screens that fits perfectly for each size.

Easy enough then ; just generate random coordinates and check the distance between the centres is less than the sum of the two radii. Probably an idea to have a retry count just in case it gets too full.

after much tinkering with my code, i have gotten into this

local gridX = {170.65, 511.95, 853.25} local gridY = {192, 576} --loop instantiate holeborder depend on which world local number = {} local numbPos = {1, 2, 3, 4, 5, 6} for i = 1, 6 do number[i] = numbPos[math.random(#numbPos)] print(number[i], 'random number') table.remove(numbPos, table.indexOf(numbPos, number[i])) end for i = 1, world do local shapes = tonumber(puzzleCode[i]:sub(4,5)) local colors = tonumber(puzzleCode[i]:sub(1,2)) local levels = tonumber(puzzleCode[i]:sub(7,8)) local x, y local randomnum = number[math.random(#number)] if randomnum == 1 then x = gridX[1] y = gridY[1] elseif randomnum == 2 then x = gridX[2] y = gridY[1] elseif randomnum == 3 then x = gridX[3] y = gridY[1] elseif randomnum == 4 then x = gridX[1] y = gridY[2] elseif randomnum == 5 then x = gridX[2] y = gridY[2] elseif randomnum == 6 then x = gridX[3] y = gridY[2] end puzzleCoor[i].x = math.random(-30, 40) + x puzzleCoor[i].y = math.random(-40, 40) + y table.remove(number, table.indexOf(number, randomnum)) print('x', puzzleCoor[i].x, 'y', puzzleCoor[i].y)

more or less, the code divide the device resolution into big chunks of area, which later be randomize inside the area, by adding a random number or range inside it. not really smart, but enough to complete what I wanted to :slight_smile: