Add multiple simillar objects

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.

but how do I move all group of objects?

You either move them individually or you move the group where all of them are placed.

object[1].x = object[1].x + 10

Of course, to move them individually, you’ll need to have a reference to each object. If you just want to move them all, then you can move the display group via:

myGroup.x = myGroup.x + 10

But when I changed “zombie” to “enemyGroup” in my runtime function weird things happen zombies don’t go to center but they just rotate weirdly and move out of the screen…
My original function:

    local function enemy()
      if zombie.removeSelf then
        if zombie.x < display.contentCenterX then
          zombie.x = zombie.x + 1
        end
        if zombie.y > display.contentCenterY then
          zombie.y = zombie.y - 1
        end
        if zombie.x > display.contentCenterX then
          zombie.x = zombie.x - 1
        end
        if zombie.y < display.contentCenterY then
          zombie.y = zombie.y + 1
        end
        zombie.rotation = 90 + math.deg(math.atan2(zombie.y - hero.y, zombie.x - hero.x))
      end
    end

And changed function:

    local function enemy()
      if zombie.removeSelf then
        if zombie.x < display.contentCenterX then
          enemyGroup.x = enemyGroup.x + 1
        end
        if zombie.y > display.contentCenterY then
          enemyGroup.y = enemyGroup.y - 1
        end
        if zombie.x > display.contentCenterX then
          enemyGroup.x = enemyGroup.x - 1
        end
        if zombie.y < display.contentCenterY then
          enemyGroup.y = enemyGroup.y + 1
        end
        enemyGroup.rotation = 90 + math.deg(math.atan2(zombie.y - hero.y, zombie.x - hero.x))
      end
    end

Have a look at bellow help 101 tips… number 8 might be what you are looking for, though all are great tips to remember: [Tips] Optimization 101

I have return in my enemy creation function. And my issue is what enemies move, but not to the center.

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

I think you might have a look at anchor points and display group positioning.
As far as i can tell, your code looks fine, except I am not sure about the naming of group here:
local zombie = display.newImage( group…
Group might be reserved keyword so I would perhaps put it in a local variable first local myGroup = group, so the code would be:
local zombie = display.newImage( myGroup…

I would like to see some response from more experienced coders, If this is necessary or not though.

I changed it, seems no result. But anyways, thanks for help :slight_smile:

I think I know where is the issue I am moving whole group at once, but I need to move all group, but invidually.

so is there way to do it?

Firstly, for @ConveyedRex7592, I already explained how you’d access display objects that have been added to a table. For instance, if you added them to a table using number keys, then you’d just refer to them like object[1].x = object[1].x + 10.

It really seems like you would benefit from some tutorials. This isn’t a criticism, this is just me trying to help you out. Take a look at https://docs.coronalabs.com/tutorial/ (especially the Getting Started Guide). I feel like you’d benefit greatly from going through that.


@Odisej That link provides a lot of good tips, but there are some mistakes, typos and oversights, especially with tip #8.

This is a bit off topic, but, for instance, the spawnAGuy “Best example”, would crash if a table isn’t passed to the function. Making it crash proof would be as simple as:

local function spawnAGuy(params) 
  local params = params or {} -- if params isn't passed, create an empty table.
  local guy = display.newImage("guy.png")  
  guy.x = params.x or 100 -- without params table, this line would crash.
  guy.y = params.y or 100  
  
  if params.group then  
    params.group:insert(guy) -- there was a typo here.
  end  
  
  return guy  
end

Now, we can remove the display objects even if we don’t return anything from the function by simply removing the display group that they are added to. This happens because Lua’s garbage collector will remove objects from memory if they no longer have a reference to them. If we don’t explicitly assign a reference to the display objects that we create, then there will only be a reference to them in the display.group (or stage) that they are added to.

In either of my two examples above, whether you remove all direct references or just the display group where the objects are, the memory footprint will be the same.

Now, finally, there’s another big issue with tip #8 concerning the destroy() method. Here’s a simplified version of it:

local function spawnARect()
    local rect = display.newRect(100,100,100,100)
    function rect:destroy()
        display.remove(self)
        self = nil
    end
    return rect  
end  

local spawnedRect = spawnARect()
spawnedRect:destroy()
print( spawnedRect ) -- It still exists even though we just destroyed it?

This is actually something that I was asking about for myself last year or the year before that, so we are all continually learning. :stuck_out_tongue:

The problem with this method is that it while it can remove the display object via a refence to itself, it cannot set itself to nil because of how tables work in Lua. Essentially, self is another reference to the same display object (table) as with spawnedRect. However, in Lua, you must explicitly set each reference to a table to nil before the table actually becomes nil.

In other words, the destroy() method sets a reference to the display object that only exists within the function to nil, but it doesn’t affect the references outside of the function at all. Now, there are ways to get it to properly destroy itself, but I’ve already rambled far too long about this off-topic issue. :smiley:

I found a solution in https://docs.coronalabs.com/guide/programming/03/index.html#gameloop !
Thanks for help.

1 Like

I put together the beginnings of a basic game that demonstrates several best practices.

It is not a complete game, there is no goal and I did not add bullets, although there is a fire button.

Instead this is an example to examine, tweak, pull apart and perhaps to add to.

https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2020/08/zombieGameHelp.zip

2 Likes

Thanks! It will be useful for sure