Generating multiples of the same display object question

So I have a question about generating multiple objects of the same image. This is not by any means supposed to be random objects either. The obstacles, which are controlled by local functions, are random. Not the images that form them though. So In the scene:create, I am creating 14 display objects which I set the isVisible to false so I can load the class. Then when an obstacle function is selected by random generation, it sets the isVisible to true for the objects that form the obstacle. So an example would be, I used 4 of the 14 images and organized them to make up an obstacle for the player to go around or go through.

The issue is that lets say I have two obstacle functions that get called right after each other. One particular display object is in both of those functions, lets say obj4. If the object gets removed in the first function while the second is generated off screen, then that display object wont be in the second function. Or if the second function gets called before the first is finished, the object in the first function is removed and is generated in the second. I know this is because I am using one display object in multiple functions.

So my question is how would I generate multiples of the same object? I’m not looking to make it random generation. I’ve placed these objects in a particular order for game play reasons. I just need to be able to have multiples of the same image generate in different functions, without having to code multiples of the same image just with different variable names. I am trying to keep my texture memory in check. Here is an example of my code:

-- Inside the scene:create op4 = display.newImageRect(sceneGroup, "levels/normalMode/level1/ast4.png", 385, 539) op4.isVisible = false op4.isBodyActive = false camera:add(op4, 3) op6 = display.newImageRect(sceneGroup, "levels/normalMode/level1/ast6.png", 340, 335) op6.isVisible = false op6.isBodyActive = false camera:add(op6, 3) op14 = display.newImageRect(sceneGroup, "levels/normalMode/level1/ast14.png", 604, 653) op14.isVisible = false op14.isBodyActive = false camera:add(op14, 1) -- Inside my scene:show did function, is randomly selected by number generation assigned -- to particular methods. local opMove4 = function() physics.addBody(op4, "kinematic", physicsData:get("ast4") ) physics.addBody(op6, "kinematic", physicsData:get("ast6") ) physics.addBody(op14, "kinematic", physicsData:get("ast14") ) op4.x = W/2 + 1250 op4.y = H/2 + 450 op4.isVisible = true op4.isBodyActive = true op4.type = "obstacle" op6.x = W/2 + 1800 op6.y = H/2 - 420 op6.isVisible = true op6.isBodyActive = true op6.type = "obstacle" op14.x = W/2 + 1450 op14.y = H/2 - 50 op14.isVisible = true op14.isBodyActive = true op14.type = "obstacle" local function rotate() transition.to(op14, {time = 2000, rotation = op14.rotation-360, onComplete = rotate, tag = "transTag"}) end rotate() local function targetRemove(target) target.isVisible = false target.isBodyActive = false physics.removeBody(target) end transition.to(op4, {time = 8000, x = W/2 - 2250, onComplete = targetRemove, tag = "transTag"}) transition.to(op6, {time = 8000, x = W/2 - 1700, onComplete = targetRemove, tag = "transTag"}) transition.to(op14, {time = 8000, x = W/2 - 2000, onComplete = targetRemove, tag = "transTag"}) end local opMove5 = function() physics.addBody(op4, "kinematic", physicsData:get("ast4") ) physics.addBody(op6, "kinematic", physicsData:get("ast6") ) physics.addBody(op14, "kinematic", physicsData:get("ast14") ) op4.x = W/2 + 1250 op4.y = H/2 -200 op4.isVisible = true op4.isBodyActive = true op4.type = "obstacle" op6.x = W/2 + 1800 op6.y = H/2 - 420 op6.isVisible = true op6.isBodyActive = true op6.type = "obstacle" op14.x = W/2 + 1450 op14.y = H/2 + 300 op14.isVisible = true op14.isBodyActive = true op14.type = "obstacle" local function rotate() transition.to(op14, {time = 2000, rotation = op14.rotation-360, onComplete = rotate, tag = "transTag"}) end rotate() local function targetRemove(target) target.isVisible = false target.isBodyActive = false physics.removeBody(target) end transition.to(op4, {time = 8000, x = W/2 - 2250, onComplete = targetRemove, tag = "transTag"}) transition.to(op6, {time = 8000, x = W/2 - 1700, onComplete = targetRemove, tag = "transTag"}) transition.to(op14, {time = 8000, x = W/2 - 2000, onComplete = targetRemove, tag = "transTag"}) end

It’s pretty obvious as to what the issue is. Would I have to make a table or an array for each display object to allow me to use multiples of the same display object? Thanks for reading!

Hi @rburns629,

Well basically, if you use the same image repeatedly, you won’t increase your texture memory. It’s already cached and it will just use the same texture over and over.

As for making multiple objects, generally it’s a good idea to keep/store references to these in a table. That way, you’ll always have some easy reference to them, for example if you need to remove all of them at some point.

Hope this helps,

Brent

Hi Brent! After I had posted this I started testing with tables. I made 14 tables, one for each display object in the scene:create. In each of my obstacle functions I set the parameters for each element within those tables. So obstacle function 1 holds all parameters for the 1st element that the function is using to form the obstacle. This method works, but the obstacles still disappear is the function is called again while on screen, and starts at the beginning again. I know its because the random generator is calling the same function again. So now I am trying to restrict the random generator from selecting the same number twice but I am running into a snag. It’s not working as I thought it would. Do you know of another way? I’ll post my code down below:

-- Loads the images into memory scene:create for a = 1, objectCount do ast1[a] = display.newImageRect(sceneGroup, "levels/normalMode/level1/ast1.png", 528, 679) ast1[a].isVisible = false ast1[a].isBodyActive = false camera:add(ast1[a], 2) end for b = 1, objectCount do ast2[b] = display.newImageRect(sceneGroup, "levels/normalMode/level1/ast2.png", 569, 737) ast2[b].isVisible = false ast2[b].isBodyActive = false camera:add(ast2[b], 4) end for c = 1, objectCount do ast3[c] = display.newImageRect(sceneGroup, "levels/normalMode/level1/ast3.png", 618, 484) ast3[c].isVisible = false ast3[c].isBodyActive = false camera:add(ast3[c], 5) end -- Inside the did of scene:show, have local functions that form the different obstacles scene:show phase == did local opMove1 = function() physics.addBody(ast8[1], "kinematic", physicsData:get("ast8") ) physics.addBody(ast10[1], "kinematic", physicsData:get("ast10") ) physics.addBody(ast11[1], "kinematic", physicsData:get("ast11") ) physics.addBody(ast6[1], "kinematic", physicsData:get("ast6") ) ast8[1].x = W/2 + 1450 ast8[1].y = H/2 + 360 ast8[1].isVisible = true ast8[1].isBodyActive = true ast8[1].type = "obstacle" ast10[1].x = W/2 + 1700 ast10[1].y = H/2 - 320 ast10[1].isVisible = true ast10[1].isBodyActive = true ast10[1].type = "obstacle" ast11[1].x = W/2 + 1200 ast11[1].y = H/2 ast11[1].isVisible = true ast11[1].isBodyActive = true ast11[1].type = "obstacle" ast6[1].x = W/2 + 2050 ast6[1].y = H/2 + 50 ast6[1].isVisible = true ast6[1].isBodyActive = true ast6[1].type = "obstacle" local function targetRemove(target) target.isVisible = false target.isBodyActive = false physics.removeBody(target) end transition.to(ast11[1], {time = objSpeed, x = W/2 - 1850, onComplete = targetRemove, tag = "transTag"}) transition.to(ast8[1], {time = objSpeed, x = W/2 - 1650, onComplete = targetRemove, tag = "transTag"}) transition.to(ast10[1], {time = objSpeed, x = W/2 - 1400, onComplete = targetRemove, tag = "transTag"}) transition.to(ast6[1], {time = objSpeed, x = W/2 - 1000, onComplete = targetRemove, tag = "transTag"}) end -- Obstacle 2 local opMove2 = function() physics.addBody(ast8[2], "kinematic", physicsData:get("ast8") ) physics.addBody(ast10[2], "kinematic", physicsData:get("ast10") ) physics.addBody(ast11[2], "kinematic", physicsData:get("ast11") ) physics.addBody(ast6[2], "kinematic", physicsData:get("ast6") ) physics.addBody(ast7[1], "kinematic", physicsData:get("ast7") ) ast8[2].x = W/2 + 1200 ast8[2].y = H/2 + 200 ast8[2].isVisible = true ast8[2].isBodyActive = true ast8[2].type = "obstacle" ast10[2].x = W/2 + 1700 ast10[2].y = H/2 ast10[2].isVisible = true ast10[2].isBodyActive = true ast10[2].type = "obstacle" ast11[2].x = W/2 + 1200 ast11[2].y = H/2 - 170 ast11[2].isVisible = true ast11[2].isBodyActive = true ast11[2].type = "obstacle" ast6[2].x = W/2 + 2050 ast6[2].y = H/2 + 100 ast6[2].isVisible = true ast6[2].isBodyActive = true ast6[2].type = "obstacle" ast7[1].x = W/2 + 2450 ast7[1].y = H/2 + 400 ast7[1].isVisible = true ast7[1].isBodyActive = true ast7[1].type = "obstacle" local function targetRemove(target) target.isVisible = false target.isBodyActive = false physics.removeBody(target) end transition.to(ast11[2], {time = 8000, x = W/2 - 2050, onComplete = targetRemove, tag = "transTag"}) transition.to(ast8[2], {time = 8000, x = W/2 - 2050, onComplete = targetRemove, tag = "transTag"}) transition.to(ast10[2], {time = 8000, x = W/2 - 1600, onComplete = targetRemove, tag = "transTag"}) transition.to(ast6[2], {time = 8000, x = W/2 - 1200, onComplete = targetRemove, tag = "transTag"}) transition.to(ast7[1], {time = 8000, x = W/2 - 1000, onComplete = targetRemove, tag = "transTag"}) end -- How I randomly generate a number to select a method. Using the variable num to attempt to -- restrict using the same method twice in a row local function ranGen() local obs = {} if ast1[a].isVisible == false then obs[#obs + 1] = 1 end if ast2[b].isVisible == false then obs[#obs + 1] = 2 end if ast3[c].isVisible == false then obs[#obs + 1] = 3 end if ast4[d].isVisible == false then obs[#obs + 1] = 4 end if ast5[e].isVisible == false then obs[#obs + 1] = 5 end if ast6[f].isVisible == false then obs[#obs + 1] = 6 end local index = math.random(#obs) local obstacle = obs[index] local num = 1 if obstacle == 1 and num ~= obstacle then opMove1() num = 1 elseif obstacle == 2 and num ~= obstacle then opMove2() num = 2 elseif obstacle == 3 and num ~= obstacle then opMove3() num = 3 elseif obstacle == 4 and num ~= obstacle then opMove4() num = 4 elseif obstacle == 5 and num ~= obstacle then opMove5() num = 5 elseif obstacle == 6 and num ~= obstacle then opMove6() num = 6 elseif num == obstacle then ranGen() end end -- objGen has a value of 3000 objTimer = timer.performWithDelay(objGen, ranGen, -1)

Hi @rburns629,

I’m not entirely sure what the project needs to do, but I think there should be a way to simplify this code so that you only have one main function which generates obstacles. That might involve setting up more complex tables of data in advance, but generally speaking, the less repetitive code you can do, the better.

As for the random number picking, if you don’t want to have it pick the same number twice, just log the chosen number into another table on the first pick, then each time the random number generator is called again, check if that number exists in the table. If it does, run the generator again until it picks a number that hasn’t been chosen yet.

Best regards,

Brent

Well the display objects have to be controlled and I pick which ones I want to use based on the formation of the obstacle. I could insert all of them into a table and just insert the parameters based on the index number, but I’d still have to be able to use multiples of the same images all in different obstacle functions. I know the code is more repetitive, its a pet peeve of mine as well, but I am able to have more direct control this way. If the implementation is correct, that is.

So far, for the random number generation I have this, but still doesn’t work the way I need it. My implementation is probably wrong.

local function random() --local random = obs[math.random(#obs)]; local index = math.random(#obs) local obstacle = obs[index] local num = {obstacle} if obstacle == 1 and obstacle ~= num then opMove1() elseif obstacle == 2 and obstacle ~= num then opMove2() elseif obstacle == 3 and obstacle ~= num then opMove3() elseif obstacle == 4 and obstacle ~= num then opMove4() elseif obstacle == 5 and obstacle ~= num then opMove5() elseif obstacle == 6 and obstacle ~= num then opMove6() --[[elseif obstacle == 7 then opMove7() elseif obstacle == 8 then opMove8() elseif obstacle == 9 then opMove9() elseif obstacle == 10 then opMove10() elseif obstacle == 11 then opMove11() elseif obstacle == 12 then opMove12() elseif obstacle == 13 then opMove13() elseif obstacle == 14 then opMove14() elseif obstacle == 15 then opMove15()]]-- elseif obstacle == num then random() end end

Occasionally a number will be repeated so my obstacle will get removed prematurely, start over, then disappear again. Thanks for your help so far by the way

Hi @rburns629,

Perhaps you need to set a flag on each obstacle that says if it’s either active or not. If it’s active, make the random number chooser pick another obstacle.

Brent

That actually worked! Good thinking! Thanks a lot Brent.

Hi @rburns629,

Well basically, if you use the same image repeatedly, you won’t increase your texture memory. It’s already cached and it will just use the same texture over and over.

As for making multiple objects, generally it’s a good idea to keep/store references to these in a table. That way, you’ll always have some easy reference to them, for example if you need to remove all of them at some point.

Hope this helps,

Brent

Hi Brent! After I had posted this I started testing with tables. I made 14 tables, one for each display object in the scene:create. In each of my obstacle functions I set the parameters for each element within those tables. So obstacle function 1 holds all parameters for the 1st element that the function is using to form the obstacle. This method works, but the obstacles still disappear is the function is called again while on screen, and starts at the beginning again. I know its because the random generator is calling the same function again. So now I am trying to restrict the random generator from selecting the same number twice but I am running into a snag. It’s not working as I thought it would. Do you know of another way? I’ll post my code down below:

-- Loads the images into memory scene:create for a = 1, objectCount do ast1[a] = display.newImageRect(sceneGroup, "levels/normalMode/level1/ast1.png", 528, 679) ast1[a].isVisible = false ast1[a].isBodyActive = false camera:add(ast1[a], 2) end for b = 1, objectCount do ast2[b] = display.newImageRect(sceneGroup, "levels/normalMode/level1/ast2.png", 569, 737) ast2[b].isVisible = false ast2[b].isBodyActive = false camera:add(ast2[b], 4) end for c = 1, objectCount do ast3[c] = display.newImageRect(sceneGroup, "levels/normalMode/level1/ast3.png", 618, 484) ast3[c].isVisible = false ast3[c].isBodyActive = false camera:add(ast3[c], 5) end -- Inside the did of scene:show, have local functions that form the different obstacles scene:show phase == did local opMove1 = function() physics.addBody(ast8[1], "kinematic", physicsData:get("ast8") ) physics.addBody(ast10[1], "kinematic", physicsData:get("ast10") ) physics.addBody(ast11[1], "kinematic", physicsData:get("ast11") ) physics.addBody(ast6[1], "kinematic", physicsData:get("ast6") ) ast8[1].x = W/2 + 1450 ast8[1].y = H/2 + 360 ast8[1].isVisible = true ast8[1].isBodyActive = true ast8[1].type = "obstacle" ast10[1].x = W/2 + 1700 ast10[1].y = H/2 - 320 ast10[1].isVisible = true ast10[1].isBodyActive = true ast10[1].type = "obstacle" ast11[1].x = W/2 + 1200 ast11[1].y = H/2 ast11[1].isVisible = true ast11[1].isBodyActive = true ast11[1].type = "obstacle" ast6[1].x = W/2 + 2050 ast6[1].y = H/2 + 50 ast6[1].isVisible = true ast6[1].isBodyActive = true ast6[1].type = "obstacle" local function targetRemove(target) target.isVisible = false target.isBodyActive = false physics.removeBody(target) end transition.to(ast11[1], {time = objSpeed, x = W/2 - 1850, onComplete = targetRemove, tag = "transTag"}) transition.to(ast8[1], {time = objSpeed, x = W/2 - 1650, onComplete = targetRemove, tag = "transTag"}) transition.to(ast10[1], {time = objSpeed, x = W/2 - 1400, onComplete = targetRemove, tag = "transTag"}) transition.to(ast6[1], {time = objSpeed, x = W/2 - 1000, onComplete = targetRemove, tag = "transTag"}) end -- Obstacle 2 local opMove2 = function() physics.addBody(ast8[2], "kinematic", physicsData:get("ast8") ) physics.addBody(ast10[2], "kinematic", physicsData:get("ast10") ) physics.addBody(ast11[2], "kinematic", physicsData:get("ast11") ) physics.addBody(ast6[2], "kinematic", physicsData:get("ast6") ) physics.addBody(ast7[1], "kinematic", physicsData:get("ast7") ) ast8[2].x = W/2 + 1200 ast8[2].y = H/2 + 200 ast8[2].isVisible = true ast8[2].isBodyActive = true ast8[2].type = "obstacle" ast10[2].x = W/2 + 1700 ast10[2].y = H/2 ast10[2].isVisible = true ast10[2].isBodyActive = true ast10[2].type = "obstacle" ast11[2].x = W/2 + 1200 ast11[2].y = H/2 - 170 ast11[2].isVisible = true ast11[2].isBodyActive = true ast11[2].type = "obstacle" ast6[2].x = W/2 + 2050 ast6[2].y = H/2 + 100 ast6[2].isVisible = true ast6[2].isBodyActive = true ast6[2].type = "obstacle" ast7[1].x = W/2 + 2450 ast7[1].y = H/2 + 400 ast7[1].isVisible = true ast7[1].isBodyActive = true ast7[1].type = "obstacle" local function targetRemove(target) target.isVisible = false target.isBodyActive = false physics.removeBody(target) end transition.to(ast11[2], {time = 8000, x = W/2 - 2050, onComplete = targetRemove, tag = "transTag"}) transition.to(ast8[2], {time = 8000, x = W/2 - 2050, onComplete = targetRemove, tag = "transTag"}) transition.to(ast10[2], {time = 8000, x = W/2 - 1600, onComplete = targetRemove, tag = "transTag"}) transition.to(ast6[2], {time = 8000, x = W/2 - 1200, onComplete = targetRemove, tag = "transTag"}) transition.to(ast7[1], {time = 8000, x = W/2 - 1000, onComplete = targetRemove, tag = "transTag"}) end -- How I randomly generate a number to select a method. Using the variable num to attempt to -- restrict using the same method twice in a row local function ranGen() local obs = {} if ast1[a].isVisible == false then obs[#obs + 1] = 1 end if ast2[b].isVisible == false then obs[#obs + 1] = 2 end if ast3[c].isVisible == false then obs[#obs + 1] = 3 end if ast4[d].isVisible == false then obs[#obs + 1] = 4 end if ast5[e].isVisible == false then obs[#obs + 1] = 5 end if ast6[f].isVisible == false then obs[#obs + 1] = 6 end local index = math.random(#obs) local obstacle = obs[index] local num = 1 if obstacle == 1 and num ~= obstacle then opMove1() num = 1 elseif obstacle == 2 and num ~= obstacle then opMove2() num = 2 elseif obstacle == 3 and num ~= obstacle then opMove3() num = 3 elseif obstacle == 4 and num ~= obstacle then opMove4() num = 4 elseif obstacle == 5 and num ~= obstacle then opMove5() num = 5 elseif obstacle == 6 and num ~= obstacle then opMove6() num = 6 elseif num == obstacle then ranGen() end end -- objGen has a value of 3000 objTimer = timer.performWithDelay(objGen, ranGen, -1)

Hi @rburns629,

I’m not entirely sure what the project needs to do, but I think there should be a way to simplify this code so that you only have one main function which generates obstacles. That might involve setting up more complex tables of data in advance, but generally speaking, the less repetitive code you can do, the better.

As for the random number picking, if you don’t want to have it pick the same number twice, just log the chosen number into another table on the first pick, then each time the random number generator is called again, check if that number exists in the table. If it does, run the generator again until it picks a number that hasn’t been chosen yet.

Best regards,

Brent

Well the display objects have to be controlled and I pick which ones I want to use based on the formation of the obstacle. I could insert all of them into a table and just insert the parameters based on the index number, but I’d still have to be able to use multiples of the same images all in different obstacle functions. I know the code is more repetitive, its a pet peeve of mine as well, but I am able to have more direct control this way. If the implementation is correct, that is.

So far, for the random number generation I have this, but still doesn’t work the way I need it. My implementation is probably wrong.

local function random() --local random = obs[math.random(#obs)]; local index = math.random(#obs) local obstacle = obs[index] local num = {obstacle} if obstacle == 1 and obstacle ~= num then opMove1() elseif obstacle == 2 and obstacle ~= num then opMove2() elseif obstacle == 3 and obstacle ~= num then opMove3() elseif obstacle == 4 and obstacle ~= num then opMove4() elseif obstacle == 5 and obstacle ~= num then opMove5() elseif obstacle == 6 and obstacle ~= num then opMove6() --[[elseif obstacle == 7 then opMove7() elseif obstacle == 8 then opMove8() elseif obstacle == 9 then opMove9() elseif obstacle == 10 then opMove10() elseif obstacle == 11 then opMove11() elseif obstacle == 12 then opMove12() elseif obstacle == 13 then opMove13() elseif obstacle == 14 then opMove14() elseif obstacle == 15 then opMove15()]]-- elseif obstacle == num then random() end end

Occasionally a number will be repeated so my obstacle will get removed prematurely, start over, then disappear again. Thanks for your help so far by the way

Hi @rburns629,

Perhaps you need to set a flag on each obstacle that says if it’s either active or not. If it’s active, make the random number chooser pick another obstacle.

Brent

That actually worked! Good thinking! Thanks a lot Brent.