3

我有时在 Lua 中制作小游戏,并且经常需要将 2D 数组实现为网格或棋盘。当我想检查特定单元格周围的单元格时,我通常给二维数组一个元表,这样当 grid[outOfBoundsNum] 被索引时,它会返回一个空表而不是错误:

setmetatable(grid, {
    __index = 
    function(t, key)
        if not table[key] then
            return {}
        else
            return table[key]
        end
    end})

所以当grid[outOfBoundsNum][anything]被调用时,它会返回nil. 然后,要检查周围的单元格,我会执行以下操作:

for k, v in ipairs(neighbours) do
    local cell = grid[v[1][v[2]]
    if cell then -- check if this is actually within the 2D array
        if cell == 1 then 
            -- do something
        elseif cell == 2 then
            -- do something else
        ...
    end
end

这行得通,但对我来说似乎很尴尬。有更好或更好的方法吗?

4

2 回答 2

3

你不需要元表。

for k, v in ipairs(neighbours) do
   local cell = grid[v[1]] and grid[v[1]][v[2]]

   if cell == 1 then 
      -- do something
   elseif cell == 2 then
      -- do something else
   ... 
   end 
end 

应该做的工作。and使用逻辑和在表达式中的作用类似于 C 中的三元运算符,这是一个相对常见的 lua 习惯用法or。所以这一行相当于:

local cell = nil
if grid[v[1]]~=nil then
    cell = grid[v[1]][v[2]]
end
于 2013-03-28T20:21:01.297 回答
2

您可以编写一个forEachNeighbor()函数来获取网格、一个位置和一个函数,然后使用每个现有的neighborfield 调用它,即将循环和外部封装if在函数的第二个片段中,您可以使用如下:

forEachNeighbor(grid, position, function(cell)
    if cell == 1 then
        -- do something
    elseif cell == 2 then
        -- do something else
    ...
end)

此外,您可以提供一个at()函数,它将网格位置作为一个参数并返回相应的字段 or nil,这样grid[v[1]][v[2]]就变成了at(grid, v). 这也可以作为元方法的补充或替代来实现__index

对于元__index方法本身:首先,您可能的意思是t代替tablerawget(t, key)代替t[key](这将导致无限递归)。但正如 lhf 指出的那样,检查是完全没有必要的,因为__index只有当密钥不存在于t. 所以你可以写:

__index = function(t, key)
    return {}
end

最后一句话:

我有时用 Lua 做小游戏,经常要实现一个 2D 数组

为什么不实现一次并在其他游戏中重复使用呢?这就是模块的用途!

于 2013-03-28T16:18:10.950 回答