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

我正在尝试为 roguelike 实现一种基于速度的回合制系统。我使用了元方法设置了一个 Mob 类,以便将以下内容分配给变量将在特定网格坐标处生成地图的移动:

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

这将把 mob 的 self.turn_counter 放入一个表中。与此同时,在另一个模块中,我定义了这两个函数,这是问题的核心:

function turn.decrement_counters(dt)--在 Dungeon.update(dt) 中运行,从 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()--在 allTurnCounters 中的条目被调用为零时调用
    if whose_turn == 1 then--生成列表中的1号和2号位置仅分配给玩家
            player1.my_turn = true--打开玩家1的键
    elseif whose_turn == 2 then
            player2.my_turn = true--打开玩家2的键
    elseif whose_turn >= 3 then--3以上就是怪物的领域

    结束
end

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

allTurnCounters 表按顺序从每个生成的移动获取新条目(一个包含玩家和怪物的类,以便它们可以共享统计信息)。我的问题是:如何让 Lua 动态检索与给定 turn_counter/值相关联的表的名称,并使用它来获取回合优先权,即使我事先不知道已经过程化生成了什么或将占据生成顺序的什么位置?

我有3个想法,没有一个我在如何实现上是牢固的。一种方法可能是将整个实例表发送到另一个表中,而不仅仅是它们的 turn_counters,然后以某种方式获取一对值(表本身和表内的 my_turn),直接更新 my_turn 的值。

另一种方法可能是使用环境 _G... 。我仍在研究 PiL 的第14章,试图将其适应于我的目的,但是 value = _G[varname] 似乎是我可以用于此的一种强大的代码段。还不确定怎么用。

我最后的想法是也许编写一些字符串感应查找替换,可以获取每个移动表中的一些其他值,然后将其弹出 my_turn 的前面。例如,为每种移动类型分配一些已知模式的值,我可以在 string.find 和 string.gsub 中使用它们,以手动使代码行读取为预期的样子。看起来不太优雅。

我很幸运能在这里提出以前的 Lua/Love2D 问题,所以我想在思考时让它出现!

点赞
用户106104
用户106104

以下是我对你应该如何实现这个的建议:

1.不要使用 allTurnCounters[i],给 MOB 一个 turn_counter 属性,然后使用 allMobsSpawned[i].turn_counter。然后删除 allTurnCounters

2.不要在 whose_turn 中存储 mob 的数量,而是存储 mob 本身。(注意:当我说 “mob 本身” 时,它是指 “对 mob 本身的引用”)

所以,不是

whose_turn = i

而是

whose_turn = allMobsSpawned[i]

3.现在,whose_turn 保存了当前轮流动的 mob。你可以轻松地检查 whose_turn == player1whose_turn == player2 等。而且,它不再仅仅依赖于玩家是第一个 mob。

你可以通过 whose_turn 访问 MOB 的属性 - 如果 whose_turn == player1 为真,例如,则 whose_turn.x 访问与 player1.x 相同的字段

2016-09-08 03:15:48
用户6792335
用户6792335

下面是一种比较简陋的解决方案,可以通过结合其他答案中的方法来使其更加优美。这是我在等待答案时自己想出来的。

-- 在 “Mob.lua” 模块中
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 -- 标记回合结束
     turn_active = false -- 标记没有活动回合
end

-- 在 “turn.lua” 模块中
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,那么事情会变得更简单,并且可以进行未来的扩展。该答案仅适用于特定的 player1、player2 和一个叫做 ant1 的蚂蚁。

2016-09-08 06:25:14