Reputation: 1111
I sometimes make small games in Lua, and often have to implement a 2D array as a grid or a board. When I want to check the cells surrounding a particular cell I usually give the 2D array a metatable so that when grid[outOfBoundsNum] is indexed it returns an empty table instead of an error:
setmetatable(grid, {
__index =
function(t, key)
if not table[key] then
return {}
else
return table[key]
end
end})
So when grid[outOfBoundsNum][anything]
is called, it returns nil
. Then, to check surrounding cells I do something like this :
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
This works, but it seems awkward to me. Is there a nicer or better way of doing it?
Upvotes: 3
Views: 1350
Reputation: 96
You don't need the metatable.
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
Should do the job. It is a relatively common lua idiom to use logical and
and or
in expressions to act like the ternary operator in C.
So this line is equivalent to:
local cell = nil
if grid[v[1]]~=nil then
cell = grid[v[1]][v[2]]
end
Upvotes: 3
Reputation: 3249
You could write a forEachNeighbor()
function which would take the grid, a position and a function and then call it with each existing neighborfield, i.e. encapsule the loop and the outer if
in your second snippet in a function, you would use like:
forEachNeighbor(grid, position, function(cell)
if cell == 1 then
-- do something
elseif cell == 2 then
-- do something else
...
end)
Also, you could provide an at()
function which would take a grid position as one parameter and return the corresponding field or nil
, so that grid[v[1]][v[2]]
becomes at(grid, v)
. This could also be implemented in addition to or instead of the __index
metamethod.
For the __index
metamethod itself: First, you probably meant t
instead of table
and rawget(t, key)
instead of t[key]
(which would cause infinite recursion).
But as lhf pointed out, the check is altogether unnecessary, because __index
is only called when the key is not present in t
. So you could just write:
__index = function(t, key)
return {}
end
One last remark:
I sometimes make small games in Lua, and often have to implement a 2D array
Why don't you implement it once and reuse it in other games? That's what modules are for!
Upvotes: 2