Lua元表:类字段与实例字段

我正在使用Corona/Lua制作一个游戏,并实现了一个名为“Item”的类,用于表示游戏中的武器、装甲、护身符等,但是我对面向对象的Lua不熟悉。

创建类的新实例后,我发现设置对象的某些属性似乎将它们设置到类元表中,而不是对象本身。

以下是类和构造函数:

local Item = {
    name = nil,
    itemType = nil,
    scarcity = "basic",
    baseDamage = 0, -- Bow only
    bonuses = {
        damageBonus = 0,
        speedBonus = 0,
        critBonus = 0,
        dropBonus = 0,
        rechargeBonus = 0,
        xpBonus = 0
    }
}

-- Creates a simple blank instance of the Item class.
function Item:new(o)
    local item = o or {}
    setmetatable(item, self)
    self.__index = self
    return item
end

现在假设我基于此原型创建了两个对象:

local bow = Item:new()
bow.itemType = "bow"
starterBow.baseDamage = 5

local ring = Item:new()
ring.itemType = "ring"
ring.bonuses.damageBonus = 0.25

令人沮丧的是,“bonuses.damageBonus”属性似乎被设置在元表中,因此应用于每个项目(即弓也获得伤害奖励,并与戒指叠加)。然而,该行为似乎仅限于“bonus”属性。如果我设置“itemType”属性,则如预期那样附加到对象而不是类。

我想看到的行为是可以针对个别项目设置“bonuses”表的字段。您知道我做错了什么吗?谢谢!

点赞
用户258523
用户258523

bonuses 表在实例中不存在,所以查找时会在元表中查找,并在 __index 表中找到它。然后继续在该表中查找。类似地,赋值也是一样的。然而只有一个 bonuses 表,这是关键,因为你从未复制它,唯一存在的副本是在 Item 类中,然后通过 __index 元表查找找到它。

你可以为每个实例添加 __index 元表魔法(对于默认值但局限于实例的赋值),也可以为每个实例简单地复制/创建新的 bonuses 表。

2014-05-07 18:51:59
用户3585949
用户3585949

__index 元字段会在你试图从表格中获取一个不存在的字段时触发。 ring.bonuses.damageBonus = 0.25 试图从 ring 获取 bonuses,由于它不存在,会去元表中查找并返回你的 bonuses 表格,然后将它的 damageBonus 索引设置为 0.25。

要理解的是,仅在 Item 表格中声明变量并不意味着你的 Item 实例会将它们作为实例变量继承。为此,你需要在 Item:new() 函数中声明/初始化它们:

function Item:new(o)
    local item = o or {}
    setmetatable(item, self)
    self.__index = self
    item.bonuses={} -- 创建实例 bonuses 表格并设置默认值
    for k,v in pairs(self.bonuses) do
        item.bonuses[k]=v
    end
    return item
end
2014-05-07 18:57:51