Search code examples
luametatable

lua metatable help (generating monsters within game)


I am having trouble using a metatable to create new monsters for a game, I can create an exact copy but I can't generate a new rat or lizard for example with a new id.

local monsters = {
  rat = {
   name = "a rat",
   id = 1,
   health = 5,
   }
  lizard = {
   name = "a lizard",
   id = 1,
   health = 8,
   }
 }

local metamonsters = {__index = monsters}
setmetatable(monsters, metamonsters)

function monsters:new(o)
 setmetatable(o, metamonsters)
 return o
end 

local testrat = monsters:new({rat})         
print(testrat.name, testrat.id)

This creates a new rat under the variable testrat, and the console prints "a rat" and "1". I can't work out how to specify a new id number for the rat when its created. Any help would be appreciated, metatables are confusing me like mad!


Solution

  • You need to begin at the basics of how classes in Lua work:

    An instance object has a meta-table meta, which contains all the meta-method, specifically __index.

    The __index meta-method is always called when a lookup in object fails to find the lookup-key.
    Actually, it need not be a function, another table is acceptable too, and we have an ideal candidate: meta.

    This game of looking whether __index in the meta-table has an entry for the key can be repeated:
    Thus, a generic monster can be meta-table to rat, which can be the meta-table for all rats.

    More and deeper inheritance can be done, if wanted.

    protos = {}
    monsters = {}
    protos.monster = {
        name = 'generic monster',
        bp = 'monster',
        health = 1,
        __call = function(self, new, proto)
            if proto then
                proto = protos
                protos[new.bp] = new
                protos[new.name] = new
            else
                proto = monsters
            end
            table.insert(proto, new)
            new.id = #protos
            return setmetatable(new, self)
        end
    }
    protos.monster.__call(nil, protos.monster, true)
    
    protos.monster({
        name = "a rat",
        short = 'rat',
        health = 5,
    }, true)
    protos.rat({
        name = "a black rat",
        short = 'blackrat',
        health = 7,
    }, true)
    

    Create a new monster with

    protos[type] { --[[ some stats here ]] }
    

    Create a new prototype with

    protos[type]({ --[[ some stats here ]] }, true)
    

    Lua manual: http://www.lua.org/manual/5.2/
    Lua-users wiki (Sample Code): http://lua-users.org/wiki/SampleCode