如何动态检索用于初始化实例的变量?

How can I dynamically retrieve the variable used to initialize an instance?

我正在尝试为 roguelike 实现基于速度的转弯系统。我已经使用元方法设置了一个生物 class,因此将以下内容分配给一个变量将在特定网格坐标处将生物生成到地图中:

function Mob:spawn(x,y,m)
    local mob = {}
    setmetatable(mob, Mob)
    mob.x = x
    mob.y = y
    mob.is_monster = m
    return mob
end

完成后,我调用以下命令:

function Mob:roll_call()
    who_is_here[self.y][self.x] = self.is_monster
    self.turn_counter = self.turn_counter * math.random(0.9, 1.1)
    table.insert(allTurnCounters, self.turn_counter)
end

这会将生物的 self.turn_counter 变成 table。同时,在另一个模块中,我定义了这两个函数,问题的核心:

function turn.decrement_counters(dt) -- runs in Dungeon.update(dt) and subtracts from allTurnCounters
    for i = 1,#allMobsSpawned do
            if allTurnCounters[i] <= 0 then
                    allTurnCounters[i] = 0
                    turn_active = true
                    whose_turn = i
                    return
            elseif allTurnCounters[i] > 0 then
                    allTurnCounters[i] = allTurnCounters[i] - (10 * dt)
            end
    end
end

function turn.whose_is_it() -- called when an entry in allTurnCounters goes zero
    if whose_turn == 1 then -- spots 1 and 2 in the spawn list are only ever for players
            player1.my_turn = true -- turns on player 1's keys
    elseif whose_turn == 2 then
            player2.my_turn = true -- turns on player 2's keys
    elseif whose_turn >= 3 then -- above 3 we're in monster territory

    end
end

我已经决定要初始化的前两个 Mob 实例将始终是玩家 1 和 2,分别分配给变量 player1 和 player2。而且,实际上,它可以很好地在玩家之间来回传递控制权!但显然,这对于一款功能齐全的游戏来说还不够。我也需要怪物

allTurnCounters table 按顺序从每个生成的生物中获取新条目(class 其中包括玩家和怪物,因此他们可以共享统计数据)。这是我的问题:如何让 Lua 动态检索与 table 中给定 turn_counter/value 关联的 table 的名称,并使用它轮流优先,即使我不知道什么是提前生成的或者它将在生成顺序中占据什么位置?

我有 3 个想法,none 我很清楚如何实施。一种方法类似于将整个实例 table 发送到另一个 table,而不仅仅是它们的 turn_counters,然后以某种方式获取一对值(table 本身和my_turn 在 table 中),直接更新 my_turn 的值。

另一种方法可能是以某种方式使用环境 _G...。我仍在仔细研究 PiL 的第 14 章,试图根据我的目的对其进行调整,但 value = _G[varname] 似乎是一段功能强大的代码,我可以将其用于此目的。还不确定如何。

我最后的想法可能是编写某种字符串感知查找替换,它可以在每个生物的 table 中获取一些其他值,然后将其弹出到 my_turn 的前面。就像,为每种生物类型分配一些具有已知模式的值,我可以在 string.find 中使用,然后在 string.gsub 中使用,以喜欢...手动使代码行按预期读取。不过看起来不够优雅。

我很幸运在这里问了我之前的 Lua/Love2D 问题,所以我想在我思考的时候把它扔出去!

以下是我对您应如何实施的建议:

  1. 而不是 allTurnCounters[i],给生物一个 turn_counter 属性 并使用 allMobsSpawned[i].turn_counter。然后,删除allTurnCounters.

  2. 不是在 whose_turn 中存储生物编号,而是存储生物本身。 (注意:当我说"the mob itself"时,它是"a reference to the mob itself"的缩写)

    所以不用

    whose_turn = i
    

    你会:

    whose_turn = allMobsSpawned[i]
    
  3. 现在whose_turn持有轮到它的暴民。您可以轻松检查 whose_turn == player1whose_turn == player2 等。作为奖励,它不再依赖于玩家成为第一批暴民。

您可以通过 whose_turn 访问生物的属性 - 例如,如果 whose_turn == player1 为真,则 whose_turn.x 访问与 player1.x

相同的字段

这是一个有点笨拙的解决方案,可以通过结合其他答案中的方法使其更加优雅。这是我在等待答案时自己想出的。

-- in "Mob.lua" module
function Mob:roll_call()
    who_is_here[self.y][self.x] = self.is_monster
    self.turn_counter = self.turn_counter * math.random(0.9, 1.1)
    table.insert(allMobs, {self.name, self.turn_counter})
    if self.is_monster == true then
        table.insert(allMonsters, {self.name, self.turn_counter})
    end
end

    function Mob:move(dx, dy)
     who_is_here[self.y][self.x] = nil
       self.x, self.y = self.x + dx, self.y + dy
       who_is_here[self.y][self.x] = self.is_monster
       self.turn_counter = 1 * self.speed
       for k,v in ipairs(allMobs) do
         if v[1] == self.name then
            v[2] = self.turn_counter
         end
     end
     self.my_turn = false -- flags turn is over
     turn_active = false -- flags no active turn
    end

-- in "turn.lua" module 
function turn.decrement_counters(dt)
    if turn_active == false then
        for k,v in ipairs(allMobs) do
            v[2] = v[2] - (10 * dt)
            if v[2] < 0 then
                v[2] = 0
                turn_active = true
                whose_turn = v[1]
                return
            end
        end
    else turn.whose_is_it()
    end
end

function turn.whose_is_it()
    if whose_turn == player1.name then
        player1.my_turn = true
    elseif whose_turn == player2.name then
        player2.my_turn = true
    elseif whose_turn == ant1.name then
        ant1.my_turn = true
    end
end

turn.whose_is_it() 是需要改进的部分。如果我使用 immibis 的分配 allMobs[i].turn_counter 的方法,那将大大简化事情并允许将来扩展。此答案仅适用于玩家 1、玩家 2,尤其是一只名为 ant1 的蚂蚁。