Preload game assets

This thread has motivated me to finally finish an article I started a while ago.  Finally published here.

Thanks!

Thank you! I just read the post. It’s awesome and helps a lot! If I run into any issues I’ll post in here again. In the future will you be adding to the tutorial? Like an advanced one? I saw that you talked about Sprite swapping so seeing one where you handle characters would be amazing. There is no good character selection tutorials out there dealing with pools like you have. Would be awesome to see one. Thanks for your help, I really appreciate it.

Sure!  Thanks for reading it and for the motivation. I had this half-written article on the back-burner for a while.

I did think about a follow-up article… probably will happen at some point in the near future.

Glad I could help.

Thanks!

–John

You’re welcome! So I tried it out and I am running into an issue. So lets say obstacle 1 spawns and before that gets to the x coordinate I need it to be at to set eveeything to false, another spawns due to random generation. When The first object finally reaches that point, it sets isVisible to false for both even though the second object is still in the middle of gameplay. Is there a way I can restrict the random generation from choosing the same number until the image visible is false? So lets say:

if random == 1 then opMove1()

  if op1.isVisible == true then

    (Restrict from generating 1 until isVisible is to false)

  end

end

I’m not fully sure I understand, but let me give it a shot.

If you want to prevent the random generator from using a number, you can do it a few ways.  Best way depends on your game situation:

  1. You can write a loop to let math.random return a number and then check to see if it is allowed.  This is ok for a few instances, but might become a problem if you want to exclude a lot of numbers.
  2. Change math.random() to return values outside of the excluded numbers.
  3. Create a temporary table of valid numbers, and return a random number from 1 to length of table, then use the value at that index.  Ex: myValue = TempIntTable[math.random(1, #TempIntTable)]

I am not sure if/how this relates to your object pooling question, since the pool will never return an object already in use, and the position of the object in the table is nothing you should be worrying about.  If you need to track more than one live object on the screen, you will need to manage that by using multiple variables for each object, or another table of live objects.

In my game Space Mission Survival, I let the physics functions tell me which enemy was hit and return that enemy to the pool.

I have another game with an 8x8 grid of tiles that’s not under control of physics, and I store the reference to those tiles in a table called LiveTiles and I added a few properties (such as isAlive, isMoving, currentRow, currentColumn) to assist me with managing which tiles to move and remove from the screen when needed.

Hope this help.

If I didn’t understand your question, please let me know.

I’ll post the code so you can see what I’m doing. My game is an endless runner so the obsatcles last until the player dies. In addition to that I am using 15 different obstacle images. Every obstacle has its own style and size. Here is the code I am using right now:

-- Located in the scene:create to load in the obstacle. Have 15 different images op1 = display.newImageRect(sceneGroup, "levels/normalMode/level1/obstacle1.png", 491, 450) op1.isVisible = false op1.isBodyActive = false --[[Located in scene:show, methods controling each individual obstacle due to them having their own animations or rotations. Obstacles travel off screen to the x coordinate of screen width-2500 then gets cycled out]]-- local opMove1 = function() physics.addBody(op1, "kinematic", physicsData:get("obstacle1") ) op1.x = 1000 op1.y = 200 op1.isVisible = true op1.isBodyActive = true op1.type = "obstacle" local function op1Remove(target) op1.isVisible = false op1.isBodyActive = false physics.removeBody(target) end transition.to(op1,{time = 12500,x=(W-2500), onComplete = op1Remove, tag = "transTag"}) end -- The random selection and generation of the obsstacles local function ranGen() local obs = {1, 2, 3, 4, 5, 6} local index = math.random(#obs) local obstacle = obs[index] if index == 1 then opMove1() if op1.isVisible == true then table.remove(obs, 1) elseif op1.x == (W-2500) then table.insert(obs, 1, 1) end elseif index == 2 then opMove2() if op2.isVisible == true then table.remove(obs, 2) elseif op2.x == (W-2500) then table.insert(obs, 2, 2) end elseif index == 3 then opMove3() if op3.isVisible == true then table.remove(obs, 3) elseif op3.x == (W-2500) then table.insert(obs, 3, 3) end elseif index == 4 then opMove4() if op4.isVisible == true then table.remove(obs, 4) elseif op4.x == (W-2500) then table.insert(obs, 4, 4) end elseif index == 5 then opMove5() if op5.isVisible == true then table.remove(obs, 5) elseif op5.x == (W-2500) then table.insert(obs, 5, 5) end elseif index == 6 then opMove6() if op6.isVisible == true then table.remove(obs, 6) elseif op6.x == (W-2500) then table.insert(obs, 6, 6) end else end end objTimer = timer.performWithDelay(2500, ranGen, -1)

So what’s happening is math.random chooses a number, continues to go through iteration, but sometimes calls lets say 3, then 3 again right afterwards. This makes obstacle 3 vanish and restart at the beginning before it reaches the point of where isVisible = false and isBodyActive = false. Multiple obstacles are selected before one another goes off screen. At one given time 3 obstacles could be on screen, so I am trying to restrict it from choosing the same number to avoid it calling a method twice if that method/obsatcle is still on screen.

Can something like this be done using your pooling method if I were to make a random selection of the images and use a get.width and get.height for the display.newImageRect()? Something like:

local obs = {{filename = "normalMode/level1/obstacle5", width = 598, height = 450, tag = "obstacle5"}, {filename = "normalMode/level1/obstacle4", width = 562, height = 450, tag = "obstacle4"}, {filename = "normalMode/level1/obstacle6", width = 379, height = 396, tag = "obstacle6"}, {filename = "normalMode/level1/obstacle2", width = 478, height = 450, tag = "obstacle2"}, {filename = "normalMode/level1/obstacle1", width = 491, height = 450, tag = "obstacle1"}} local index = math.random(#obs) local obstacle = obs[index] local obstacles = 15 local obj = {} for i = 1, obstacles do obj[i] = display.newImageRect(sceneGroup, obstacle.filename..".png", obstacle.width, obstacle.height); obj[i].isVisible = false obj[i].isBodyActive = false end

Using this method doesn’t allow me to preload the images using composer.loadScene(), so I’d have to use display.newImage to get the width and heigh of the image then call it into that method. Thanks for your help, I appreciate it!!!

Pooling just allows you to preload images/physics so you don’t have to create/recreate them during game play.  Everything else should be handled exactly as before.

Looking at your code, I would do this (note that I didn’t run or test this so it might need a bit of tweaking):

In function randGen, Line 28, determine what valid numbers can be called:

[lua]

local obs = {}

if ob1.isVisible then obs[#obs + 1] = 1

if ob2.isVisible then obs[#obs + 1] = 2

if ob3.isVisible then obs[#obs + 1] = 3

if ob4.isVisible then obs[#obs + 1] = 4

if ob5.isVisible then obs[#obs + 1] = 5

if ob6.isVisible then obs[#obs + 1] = 6

local index = math.random(#obs)

local obsticle = obs[index]

[/lua]

…so, in your example, if “3” was returned, the next time obs would be {1, 2, 4, 5, 6}, so “3” cannot be returned until that object is off screen.

–john

   

Here is what I have so far:

local function ranGen() local obs = {} if op1.isVisible == false then obs[#obs + 1] = 1 elseif op2.isVisible == false then obs[#obs + 1] = 2 elseif op3.isVisible == false then obs[#obs + 1] = 3 elseif op4.isVisible == false then obs[#obs + 1] = 4 elseif op5.isVisible == false then obs[#obs + 1] = 5 elseif op6.isVisible == false then obs[#obs + 1] = 6 end --local random = obs[math.random(#obs)]; local index = math.random(#obs) local obstacle = obs[index] if obstacle == 1 then opMove1() if op1.isVisible == true then table.remove(obs, 1) end end if obstacle == 2 then opMove2() if op2.isVisible == true then table.remove(obs, 2) end end if obstacle == 3 then opMove3() if op3.isVisible == true then table.remove(obs, 3) end end if obstacle == 4 then opMove4() if op4.isVisible == true then table.remove(obs, 4) end end if obstacle == 5 then opMove5() if op5.isVisible == true then table.remove(obs, 5) end end if obstacle == 6 then opMove6() if op6.isVisible == true then table.remove(obs, 6) end end end

This will iterate through the obstacles exactly like you said, but its not random. It goes through the iteration of them so 1-6. I’m not going to complain about that though considering I’ll have 30 or more obsatcles so the player may never even see the repeat of number iterations. Your help has been absolutely amazing, truly. You definely helped me get through a hurdle. I am beyond grateful. Do you see the change you’d make to make it random again?

I think the problem is the if statement at line 4… You want to build a table of available obstacle numbers and this won’t do it. It will only create a table with one entry. I think if you remove the else if and use multiple ifs for each obstacle you will have a table of obstacles that’s are not visible that the random function can then use.

Just got it working, thanks! I just added your website to my favorites as well. I can’t even tell you how grateful I am to you. With the lag eliminated from the levels I can now move forward with adding character select and options, so this was beyond a huge help. Thank you so much. With corona now free for everyone, I hope to see more developers like you and one day be as good at dealing with tables and arrays as you are. That was a huge weaknes of mine in Advanced Programming even if I pulled a great grade. Again, thank you.

Glad to help!  It was fun and got me off my butt to finish my article as well.  :slight_smile: