Posted on by

Hey guys & gals.
I have seen a lot of posts on the forums regarding spawning of objects/display images. Some of you are having problems and others missing some key aspects regarding spawning.
This is going to be a little tutorial that explains how to spawn objects properly and allow you to manage each individually spawned object.

The concept :
The concept of spawning is to create multiple copies of a single object with each copy having it’s own individual parameters that are accessible from anywhere.

How to do it :
First things first, here is a basic spawning example that is incorrect :


local function spawn()
local object = display.newImage(“myImage.png”)
end

Why is this wrong? Well here is why. This function will create a new copy of “myImage.png” each time it is called, however the only place that it is stored is in the object variable which is created each time the function is run and local only to that function. So after spawning the object you have no way of manipulating it.
To fix this you return the object and assign it to a variable :


--Function to spawn an object
local function spawn()
local object = display.newImage(“myImage.png”)
return object
end

--Create a table to hold our spawns
local spawnTable = {}

--Spawn two objects
for i = 1, 2 do
spawnTable[i] = spawn()
end

Now that you have returned the object and assigned it to a table index, each object is now unique and can be accessed by the table :


print(spawnTable[1])
print(spawnTable[2])

The code is still pretty rigid and unusable for most purposes at present, now we will introduce the power of function parameters :


--Function to spawn an object
local function spawn(params)
local object = display.newImage(params.image)

return object
end

Now we can spawn like so:


local spawn1 = spawn(
{
image = "myImage.png"
}
)

local spawn2 = spawn(
{
image = "myImage2.png"
}
)

So we now know how to spawn an image, return it so it becomes a unique object and also have a little knowledge about using function parameters. Now lets get a little bit more advanced. Why should we have to manually copy the references to a table when we can let the function do it for us?


--Create a table to hold our spawns
local spawnTable = {}

--Function to spawn an object
local function spawn(params)
local object = display.newImage(params.image)
--Set the objects table to a table passed in by parameters
object.objTable = params.objTable
--Automatically set the table index to be inserted into the next available table index
object.index = #object.objTable + 1

--Give the object a custom name
object.myName = "Object : " .. object.index

--Insert the object into the table at the specified index
object.objTable[object.index] = object

return object
end

Now when you call the spawn function you can clearly see the magic in action :


--Create 2 spawns
for i = 1, 2 do
local spawns = spawn(
{
image = "myImage.png",
objTable = spawnTable,
}
)
end

--Now print the names of both created spawns
for i = 1, #spawnTable do
print(spawnTable[i].myName)
end

Now you can see that the output has printed :


Object : 1
Object : 2

So the function now takes care of inserting the spawn into a table and giving it a unique index. This is only the beggining though, what if you also wanted to automatically insert it into a group passed by parameters?


--Function to spawn an object
local function spawn(params)
local object = display.newImage(params.image)
--Set the objects table to a table passed in by parameters
object.objTable = params.objTable
--Automatically set the table index to be inserted into the next available table index
object.index = #object.objTable + 1

--Give the object a custom name
object.myName = "Object : " .. object.index

--The objects group
object.group = params.group or nil

--If the function call has a parameter named group then insert it into the specified group
object.group:insert(object)

--Insert the object into the table at the specified index
object.objTable[object.index] = object

return object
end

Now all we have to do to automatically insert it into a chosen group is this:


local localGroup = display.newGroup()

--Create a table to hold our spawns
local spawnTable = {}

--Create 2 spawns
for i = 1, 2 do
local spawns = spawn(
{
image = "myImage.png",
objTable = spawnTable,
group = localGroup,
}
)
end

Easy or what? Now the spawn function can automatically insert the spawn into a table, into a group and give it a unique index. How about if we wanted certain objects to also have a physical body?


--Function to spawn an object
local function spawn(params)
local object = display.newImage(params.image)
--Set the objects table to a table passed in by parameters
object.objTable = params.objTable
--Automatically set the table index to be inserted into the next available table index
object.index = #object.objTable + 1

--Give the object a custom name
object.myName = "Object : " .. object.index

--If the object should have a body create it, else dont.
if params.hasBody then
--Allow physics parameters to be passed by parameters:
object.density = params.density or 0
object.friction = params.friction or 0
object.bounce = params.bounce or 0
object.isSensor = params.isSensor or false
object.bodyType = params.bodyType or "dynamic"

physics.addBody(object, object.bodyType, {density = object.density, friction = object.friction, bounce = object.bounce, isSensor = object.isSensor})
end

--The objects group
object.group = params.group or nil

--If the function call has a parameter named group then insert it into the specified group
object.group:insert(object)

--Insert the object into the table at the specified index
object.objTable[object.index] = object

return object
end

So basically what we have done there is add an extra parameter that basically says, if a parameter named “hasBody” is passed then add a body with specified paramenters. If those paramenters don’t exist then revert to default parameters.

Here it is in action :


local localGroup = display.newGroup()

--Create a table to hold our spawns
local spawnTable = {}

--Create 2 spawns
for i = 1, 2 do
local spawns = spawn(
{
image = "myImage.png",
objTable = spawnTable,
hasBody = true,
friction = 0.4,
bounce = 0.4,
bodyType = "static",
group = localGroup,
}
)
end

Now we have created a spawn with a physical body. Notice how I ommited some parameters? Thats the beauty of using parameters. You don’t *have* to explicitly call them. I was happy with density being 0 so I didn’t specify it, i didnt want the object to be a sensor so i didn’t specify it, so it reverted to the default of false.

Using the parameter technique you can make hugely powerful functions (not just limited to spawning). You can push out as much or as little as you want to parameters and customize an individual spawn easilly by setting up a solid spawn function that takes care of the dirty work for you.

Hope this helps you all, any questions feel free to ask via comments :)


Posted by . Thanks for reading...

25 Responses to “How to spawn objects — the right way!”

  1. Eiswuxe

    Hey danny,

    nice and clean tutorial here!
    But I think it is essential to tell people how they can REMOVE objects properly once they become obsolete, too. Maybe you could enhance the tutorial and add this type of information. Otherwise, great work!

    Reply
  2. Mark

    Hi Danny,

    Great topic to blog about and good explanation. I was wondering if you think the following code is an ok method to spawn also:

    – move enemies down the screen and remove if y position greater than 400

    function moveEnemy(self, event)
    if(self.y > 400) then
    Runtime:removeEventListener (“enterFrame”, self )
    self:removeSelf()
    else
    self.y = self.y + 2
    end
    end

    – add the enemy and setup enterFrame event

    function addEnemy()
    local enemy= display.newImage(“enemy.png”)
    enemy.x = math.random(50,400)
    enemy.enterFrame = moveEnemy
    Runtime:addEventListener(“enterFrame”, enemy)
    end

    – add an enemy every 3 seconds

    timer.performWithDelay(3000,addEnemy,0)

    I find this way works fine and no need for tables etc….. anyway would be great to get an opinion if possible because I’d like to adhere to best practice. Love Corona!

    Mark

    Reply
  3. dm

    –The objects group
    object.group = params.group or nil

    –If the function call has a parameter named group then insert it into the specified group
    object.group:insert(object)

    What if the function call don’t have a parameter named group? ;)

    Reply
  4. danny

    Sorry the post got a little messed up, il fix it :

    That is supposed to be

    –The objects group
    object.group = params.group or nil

    –If the function call has a parameter named group then insert it into the specified group
    if params.group then
    object.group:insert(object)
    end

    Reply
  5. John

    In the very first example, am I right in saying the variable object will be destroyed when the function returns? in that case the table refering to the display object is not refered by anything and can be removed by the Garbage Collector? But I think the actual picture on screen would not dissappear? I’m confused about the difference between the lua table we can manipulate (with accessible properties like x,y etc) and the actual picture on the screen: they are not quite the same…

    Reply
  6. Sven

    Hey, great tut! Could also tell us how to remove spawned objects in a nice, non-proccessor-heavy function? :). Much appreciated!

    Reply
  7. Ross

    YES! Thanks. Now for proper removal of spawned object and life will be good.

    Thanks for sharing!

    Reply
  8. Steve

    @Danny, thanks for great post. I am still wondering how to spawn object infinitely and while the object is being spawned how can we remove and nil object that has its x > 100 (without setting up an invisible object to make collision with spawned object in order to remove spawned object).

    Steve

    Reply
  9. Luis Jose Regis Benavides

    The array is actually because we need to know where are our objects in memory so we can remove then later, i recommend something like this.

    function enterFrame()

    local c = 0
    while c<array.length
    if(array[c])
    then
    array[c].removeSelf() — Or create a user defined function
    end

    end

    The only problem with this is if you got many spawns you will have to loop through many objects.
    I have used this function because the max number of spawns per level in my game is 20 – 30 enemys, so i reset the array every level.

    Otherwise you can create a function to clean your array every time.

    Reply
  10. Steve

    You need to set the object to nil to completely remove it from memory. It works for you because you just spawn 20 – 30 objects. If you had to keep spawning object throughout your game, its hard to remove and nil object that way (I mean I never find a way to do that). You can remove the object but nil’ing the object while other objects are being spawned will generate “WARNING: Attempting to set property(1) with nil.”

    Reply
  11. Antheor

    Thx for the “right way” coding info :)

    Considering your example, I was wondering if there was some specific hints to add listeners to objects created in spawn().

    I tried to do
    object:addEventListeners (“touch”, touched), but get some errors (I must admit I don’t know if my function touched() has to be in a specific place)

    Thx !

    Reply
  12. Alan

    I keep getting a runtime error:

    attempt to index local ‘object’ (a nil value)

    stack traceback:
    [c]: ?

    I’m trying to push a class object into the table. The class and all of it functionality still works, but the terminal gives me this annoying runtime error.

    –create a table to hold our spawn
    local spawnTable = {}

    –function to spawn a customer
    local function spawnCustomer(params)
    local object = display.newImage(params.image)
    –set the objects table to a table passed in by parameters
    object.objTable = params.objTable
    –Automatically set the table index to be inserted into the next available table index
    object.index = #object.objTable + 1

    –insert the object into the table at the specified index
    object.objTable[object.index] = object

    return object
    end

    –create spawn function
    local function timedSpawn()
    for i = 1, 1 do
    spawns = spawnCustomer({image = familyImport.family(), objTable = spawnTable})
    end
    end

    local tmr = timer.performWithDelay(5000, timedSpawn, 1)

    Is there a better procedure for spawning an entire class?

    Thanks for any input!

    Reply
  13. Martian

    Hi, a little help of adding an event listener for each spawned object.
    I spawned three object and I want each object to have its own event listener.

    Thanks very much

    Reply
  14. Jarrad Thomas

    Hey Danny I’m running into an error with this particular line:

    object.index = #object.objTable + 1

    it provides the error:
    attempt to get length of field ‘objTable’ (a nil value)

    however 5 out of 6 spawn correctly

    Reply
  15. thearcherblog

    Hello All,

    Impressive tutorial, wonderful for newbie people like me :) Thanks a lot!!

    But as a “good” newbie… I need to ask a question…. what can I do if I want to attach a Text using display.newText function?… and how can I refer to it after that?

    I tried different things but… for sure… I’m doing something wrong… Can someone bring me some light on this, please?

    Thanks a lot.

    Reply
    • thearcherblog

      Sorry, maybe I didn’t explain it fine…

      I mean, the display.new image and a newText attached to it.

      What I want to have is an spawn system creating an image and a text that I can modify indepently if it’s possible.

      Thanks a lot.

      Regards!!

      Reply
  16. trey777

    hey how would i set the x and y of the objects being spawned?

    like x = 100 y = 100 for objectA and x = 200 and y = 100 for object B ?

    Reply

Leave a Reply

  • (Will Not Be Published)