Add multiple simillar objects

How do I add multiple simillar objects?
I mean how to have 2(or more) objects with same parameters(image, etc.)?
Because this doesn’t work:

local object = display.newImage(...)
object.x = ...
object.y = ...
object.hp = ...
physics.addBody(object, "dynamic")

local object = display.newImage(...)
object.x = ...
object.y = ...
object.hp = ...
physics.addBody(object, "dynamic")

Create a builder function and call the function.

local enemies = {}
local function createEnemy( group, x, y, params )
   params = params or { hp = 20 }
   local object = display.newImage( group, ... )
   object.x = x
   object.y = y
   object.hp = params.hp
   physics.addBody(object, "dynamic")
   enemies[object] = object
   return object
end

Now…

local enemyGroup = display.newGroup()

createEnemy( enemyGroup, 100 , 200 ) -- This enemy has 20 HP
createEnemy( enemyGroup, 100 , 400, { hp = 100 } )  -- This enemy has 100 HP

for k,v in pairs (enemies) do
   print( v.x, v.y, v.hp )
end
2 Likes

Thank you! And do I need to change anything in my collision function?

I haven’t seen your function, but I’m going so say, as long as all objects are of the same type and have the same behavior, they can use a generic collision listener suited to their type/category.

But what I need to add to add one more parameter like damage?
This?

    local enemies = {}
    local function createEnemy( group, x, y, params, params2 )
      params = params or { hp = 20 }
      params2 = params2 or { dmg = 10 }
      local zombie = display.newImage( group, ... )
      zombie.x = x
      zombie.y = y
      zombie.hp = params.hp
      zombie.dmg = params2.dmg
      physics.addBody(zombie, "dynamic")
      enemies[zombie] = zombie
      return zombie
    end

Now correct👍🏻

Thank you :slight_smile:

But now fuction what moves zombies ignores new zombies (built via builder)
Code from function:

if zombie.removeSelf then
  zombie.x = zombie.x + 2
end

And there is problems with collision, too.
Function:

local function zombieCollision(self, event)
      local other = event.other
      local phase = event.phase
      if( other.objType == "hero" ) then
        if( phase == "began" ) then
          hero.isColliding = true
          checkHeroCollision()
        elseif phase == "ended" then
          hero.isColliding = false
        end
      elseif( other.objType == "beam" ) then
        if( phase == "began" ) then
          zombie.hp = zombie.hp - 30
          if zombie.hp <= 0 then
            timer.performWithDelay(1, function()
              display.remove( zombie )
            end)
          end
        end
      end
    end

    zombie.collision = zombieCollision
    zombie:addEventListener("collision", zombie)

Having read your posts on other threads, you seem to be having issues with how you refer to objects in your code.

It is important to understand that if you create two objects that have the same name, then you will lose reference to the first object. For instance,

local object = display.newRect( 100, 100, 100, 100 )
object.name = "object 1"

local object = display.newRect( 200, 100, 100, 100 )
object.name = "object 2"

print (object.name ) -- prints "object 2"

However, since you didn’t remove the first object before you created the new one, so it still exists. You just can’t access it easily. The way how @roaminggamer creates enemies in his code is good because it will add the new enemies to a table where you can always access them and easily remove them.

Now, in your conditional checks and zombieCollision listener, you are checking for zombie. This means that if you ever have more than a single object named zombie in your game, then your conditional checks and collisions listener simply won’t work.

You need to design your code in a way that it will work for all objects, not just for objects with a singular reference. For instance, in your collision listener, you have self and other. So write your listener in a way that it works for the two objects that are colliding, regardless of what their names/references are.

Also, you need to pay attention to how you remove display objects.

if zombie.removeSelf then
    zombie.x = zombie.x + 2
end

This check isn’t good. If that’s all there is to it, then it may crash if zombie is nil because it is trying to access an entry within a table, but if there is no table to start out with, it’ll just crash.

If you would instead check for

if zombie then
    zombie.x = zombie.x + 2
end

Then, if you are sure that zombie can ever be used for a display object, you’d be safe from crashes for the check itself. Furthermore, if you only ever use it for display objects, then we know that if zombie exists, then it’s table entries will as well (unless you’ve somehow explicitly removed them without removing the table itself).

So in function I need to change zombie to self and in checks do if zombie then ...?

@ConveyedRex7592

You need to learn more about variables, scope, visibility, the lifetime of (display) objects, and events.

This is not a criticism, but many of the issues you are running into are grounded in these topics, which are fundamental to game development (and programming) in general and Corona/Solar 2D specifically.

If you can summarize what your game does for us, someone might help you with some examples showing best known methods for achieving your goals.

Tip: I also suggest following some tutorials that build up topic after topic from simple games to more complex games. This will help you learn these topics.

Don’t feel bad either. This is the journey we have all taken.

Ok, I will watch some tutorials about this and I think I’ve should have started from easier project.

I strongly suggest you tell us some details about what you wanted to do. You may be surprised how much help you get.

Also, I must re-iterate. Don’t feel bad or be discouraged. I promise this will make more and more sense as you go along. It will get easier.

Here’s two small examples to illustrate the issue a bit:

-- Example 1: Adding objects to a table to keep track of them.
local object = {}
local myGroup = display.newGroup()

local function removeMe( event )
    if event.phase == "ended" then
        local t = event.target
        display.remove(t)
        for i = 1, #object do
            if object[i] == t then
                table.remove( object, i )
            end
        end
    end
    return true
end

local function newObject()
    local object = display.newCircle(
        myGroup,
        math.random( 0, display.contentWidth ),
        math.random( 0, display.contentHeight ),
        math.random( 32, 48 )
    )
    object:addEventListener( "touch", removeMe )
    return object
end

for i = 1, 10 do
    object[i] = newObject()
end

In Example #1, objects are added to object table from where they can be accessed at any time. This means that when I want to remove them, I also need to remove them from the table via some means. In this case, I just loop through the table until I find the correct entry.

With this style, you always have access to any object that you create and it doesn’t matter whether you touch object #1 or object #10, the function will work regardless.

-- Example 2: Creating objects and "losing" reference to them.
local myGroup = display.newGroup()

local function removeMe( event )
    if event.phase == "ended" then
        local t = event.target
        display.remove(t)
    end
    return true
end

local function newObject()
    local object = display.newCircle(
        myGroup,
        math.random( 0, display.contentWidth ),
        math.random( 0, display.contentHeight ),
        math.random( 32, 48 )
    )
    object:addEventListener( "touch", removeMe )
end

for i = 1, 10 do
    newObject()
end

In Example #2, the objects are created, but they aren’t returned from the function. This means that a reference to them individually is lost the moment that the function which creates them finishes.

Lua garbage collector will remove objects once there are no references left to them and at this point the only reference left to them is in the display objects themselves. In other words, if I were to remove the display group or remove any of the individual display objects, the result would be the same as above. However, unlike with Example #1, there are far fewer ways of actually referencing these display objects as I don’t have an easy handle for them.


In both of these cases, the object creation and removal functions work regardless of what object you interact with.

1 Like

Ok, I understand. And here are the details.
My game idea is what player has different characters which player can unlock and different weapons which you can get after killing the boss in arena mode(boss appears after some waves, to proceed to next wave you need to kill all the zombies). And I am thinking about adding story mode(different levels, story).
My game is top view so the player character is in the middle and every other object is moving, the weapon is only rotation together with the player.

For a weapons system, I’d probably just have a variable or a table entry that states what weapon player has currently equipped, then another table for what weapons the player can choose from and a table containing information of all weapons.

For instance,

local weapons = {
    unarmed = {
        img = "fist.png",
        dmg = 1,
        range = 1
    },
    sword = {
        img = "sword.png",
        dmg = 5,
        range = 2,
    }
    -- etc.
}

local activeWeapon = weapons.unarmed

As long as you always have something set to activeWeapon, it means it’ll never be nil and you won’t have to worry about those errors from the other thread.

1 Like

Thanks for replying. I will get back to you on this. I think I can provide you (and the community) some steps to get started on such a project.

This is the work week though, so progress will be slow. Please be patient with me for now.

Yea, that’s probably better than mine.
My method:

hero.weapon1 = "empty" -- can be empty or name of the weapon
hero.weapon2 = "empty" -- can be empty or name of the weapon
hero.selectedWeapon = 0 
--  0 means no weapon equipped(melee), 1 means the first weapon equipped, 2 means second weapon equipped.
--the player can have 2 weapons at the time, if he finds better weapon then he can switch weapons

So should I change everything to your method?

I don’t quite understand what do you mean.