Search code examples
lualua-tablelove2d

Does Lua share tables within tables?


I started developing a game with Love2d engine and Lua, and I have the following code structure.

BaseEntity = { 
        x = 0,
        y = 0,
        w = 0,
        h = 0,
        img = {},
     }

function BaseEntity:new(obj)
    obj = obj or {}
    setmetatable(obj, self)
    self.__index = self
    return obj
end

function BaseEntity:setPos(x, y)
    self.x = x
    self.y = y
end

function BaseEntity:setImage( index, image )
    self.img[index] = image
end

PlayerType  = {["NORMAL"] = 0, ["AI"] = 1}
PlayerState = {["SELECTED"] = 0, ["NOT_SELECTED"] = 1}

Player =    {
                type    = PlayerType.NORMAL,
                state   = PlayerState.NOT_SELECTED
            }

Player = BaseEntity:new(Player)

function Player:new( obj )
    obj = obj or BaseEntity:new()
    setmetatable(obj, self)
    self.__index = self
    return obj
end

function Player:setImage( image )
    self.img["sprite"] = image
end

When I create a few Player objects and assign different images using setImage() function to each object, they all share the same image I assigned to the last object. But when I set different positions to each object using setPos() method, they are drawn in correct distinctive positions. Why does it happen like that? Does Lua share the table img inside BaseEntity with all its instances created from it?


Solution

  • Tables are shared. You have to create separate instance of table if you do not want to share. Note that the x, y ... img you are defining as class variables not as instance variables. To see this, try this code:

    BaseEntity = { 
            x = 0,
            img = {}, 
         }
    
    function BaseEntity:new(obj)
        obj = obj or {}
        assert(self == BaseEntity)
        setmetatable(obj, self)
        -- obj.img = {}
        self.__index = self
        -- self.__newindex = self
        return obj
    end
    
    p1 = BaseEntity:new {y = 1}
    p2 = BaseEntity:new {y = 2}
    
    print('p1:', p1.x, p1.y, p1.img)
    print('p2:', p2.x, p2.y, p2.img)
    print('base:', BaseEntity.x)
    p1.x = 3
    print('p1:', p1.x, p1.y, p1.img)
    print('p2:', p2.x, p2.y, p2.img)
    print('base:', BaseEntity.x)
    

    This produces this output:

    p1: 0   1   table: 0x1736430
    p2: 0   2   table: 0x1736430
    base:   0
    p1: 3   1   table: 0x1736430
    p2: 0   2   table: 0x1736430
    base:   0
    

    showing that the table is shared and that when you write to x, you are writing to the p1 instance not to the class. If now you uncomment the obj.img in new() the tables of p1 and p2 will no longer be the same: each instance will have its own. If you uncomment the __newindex line, you will see that you are then assigning to the BaseEntity "class"