2

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!

  • You aren't using `testrat` anywhere in that code. You are printing out the singleton `monsters.rat` on that last line. That being said testrat is going to be a weird object. Not just the rat table but a table containing a rat table at index `1`. Not that none of that has anything to do with metatables in the slightest. – Etan Reisner Oct 02 '14 at 17:29
  • If you want to create new IDs each time you create a new monster then you need to assign the id in the `new` function and not hard-code it into the rat singleton (you could use the rat singleton as the current id counter if you wanted to keep a counter for each monster type individually though I suppose). – Etan Reisner Oct 02 '14 at 17:30
  • Sorry that was a mistake in my copying of the code I changed the print line to testrat. As mentioned in the full version it does print the "default" details from the linked metatable. I will have a look at changing the new function and see if I can get it to work with assigning a new ID. Thanks. – mixedfr00tjam Oct 02 '14 at 18:33
  • You know, `local testrat = monsters:new({rat})` is equivalent to `local testrat = monsters:new {}`, because there is no global or local `rat`. – Deduplicator Oct 02 '14 at 18:39
  • I am very confused then I thought using {rat} selected the rat from the monsters table so that testrat uses the rat's stats rather than the lizard's? – mixedfr00tjam Oct 02 '14 at 18:50
  • nope. Lua does not guess for you. Anyway, I'm just writing something up. BTW: If you want to ping someone, use @mixedfr00tjam (The asker and the one on who's post you comment are always notified). – Deduplicator Oct 02 '14 at 18:53

1 Answers1

1

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

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • Cheers that's really helpful, gives me a better idea of how I should be doing things. I like the "#protos" to generate a new id number each time, it seems so obvious now but didn't even occur to me at the time! – mixedfr00tjam Oct 02 '14 at 19:31