Search code examples
objectoopluainstance

Table of Objects in Lua


I'm attempting to create a Lua object like this

Block = {x = 0, y = 0, color = "red"}

function Block:new (x, y, color)
   block = {}
   setmetatable(block, self)
   self.__index = self
   self.x = x
   self.y = y
   self.color = color
   return block
end

Then putting several instances of this object into a table in a separate file

blocks = {}
table.insert(blocks, Block:new(0, 0, 'red'))
table.insert(blocks, Block:new(2, 0, 'blue'))
table.insert(blocks, Block:new(1, 1, 'green'))

for i,v in ipairs(blocks) do
    print(i,v.x, v.y, v.color)
end

But my output is

1   1   1   green
2   1   1   green
3   1   1   green

How can I get these objects to retain their own instance in the table?


Solution

  • In your code

    Block = {x = 0, y = 0, color = "red"}
    
    function Block:new (x, y, color)
       block = {}
       setmetatable(block, self)
       self.__index = self
       self.x = x
       self.y = y
       self.color = color
       return block
    end
    

    The first problem that causes all your instances to be the same is that you did not make block local to the function. Instead each call to Block.new operates on the same global variable. So every time you call it you overwrite the result of the previous call.

    The second problem is that you do not modify your instance but the class itself. As your instances don't have x, y and color you fall back to Block's value due to __index referring to Block

    self refers to the table Block as function Block:new(x, y, color) is equivalent to function Block.new(self, x, y, color) and your function call Block:new(0, 0, 'red') is equivalent to Block.new(Block, 0, 0, 'red')

    So you try to create an instance of the Block class named block. If you want to change that instances properties you must use block.x = x instead of self.x = x as you otherwise will alter Block which then would reflect on all instances.

    Block = {x = 0, y = 0, color = "red"}
    
    function Block:new (x, y, color)
       local block = {}
       setmetatable(block, self)
       self.__index = self
       block.x = x
       block.y = y
       block.color = color
       return block
    end