Lua - 遍历 table 的问题
Lua - problems iterating through table
我正在尝试编写游戏。
要点是游戏有玩家,我会生成僵尸,它们会走向玩家。
这些是我的文件:
main.lua
local Player = require("player")
local Zombie = require("zombie")
love.window.setTitle("Shooter")
function love.load()
sprites = {}
sprites.background = love.graphics.newImage('sprites/background.png')
player1 = Player
player1.setPos(300, 300)
zombies = {}
end
function love.update(dt)
player1.move(dt)
player1.rotate()
for i, z in ipairs(zombies) do
z.rotate(player1)
z.move(dt)
end
end
function love.draw()
love.graphics.draw(sprites.background, 0, 0)
love.graphics.draw(player1.sprite, player1.position.x, player1.position.y, player1.angle, nil, nil, player1.sprite:getWidth()/2, player1.sprite:getHeight()/2)
for i,z in ipairs(zombies) do
love.graphics.draw(z.sprite, z.position.x, z.position.y, z.angle, nil, nil, z.sprite:getWidth()/2, z.sprite:getHeight()/2)
love.graphics.printf("order" ..i, 0, 50, love.graphics.getWidth(), "center")
end
end
function distance(player, enemy)
return math.sqrt((player.position.x - enemy.position.x)^2 + (player.position.y - enemy.position.y)^2)
end
function love.keypressed(key, scancode, isrepeat)
if key == "u" then
spawnZombie(zombies)
end
end
zombie.lua
local Zombie = {
position = {},
speed = 1,
angle = 0,
sprite = love.graphics.newImage('sprites/zombie.png')
}
function Zombie.setPos(x, y)
Zombie.position.x = x
Zombie.position.y = y
end
function Zombie.move(dt)
distance = Zombie.speed * dt * 60
Zombie.position.x = Zombie.position.x + math.cos(Zombie.angle) * distance
Zombie.position.y = Zombie.position.y + math.sin(Zombie.angle) * distance
end
function Zombie.rotate(player)
Zombie.angle = math.atan2(player.position.y - Zombie.position.y, player.position.x - Zombie.position.x)
end
function spawnZombie(zombieTable)
zombie = Zombie
zombie.setPos(math.random(0, love.graphics.getWidth()), math.random(0, love.graphics.getHeight()))
table.insert(zombieTable, zombie)
end
return Zombie
最后,player.lua
文件完成。
spawnZombie()
应该创建一个新僵尸并将其插入 zombies
table。 love.draw()
应该遍历 zombies
table 并将它们全部绘制出来。
我遇到了两个问题,很可能相关:
只会生成一个僵尸。
每个生成的僵尸都比最后一个快。
这可能意味着只绘制了一个僵尸(table中的第一个)并且他的速度在love.update()
函数中增加了。如果该假设是正确的,那么问题可能出在 spawnZombie()
函数中。
如何修复我的程序?
Zombie
是你唯一的僵尸。您创建的每个 "new" 僵尸实际上只是它的别名:
zombie = Zombie
不创建副本,但表示 zombie
只是同一对象的另一个名称。
您需要为每个新僵尸创建一个新的 table。您可能想要使用 方法 以便您可以对每个实例使用相同的函数。
一个方法是用:
定义的,并自动获得一个名为self
的不可见参数,它是调用该方法的对象。方法被称为 :move(0.5)
而不是 .move(0.5)
:
function Zombie:move(dt)
local distance = self.speed * dt * 60
self.position.x = self.position.x + math.cos(self.angle) * distance
self.position.y = self.position.y + math.sin(self.angle) * distance
end
要创建一个新的僵尸实例,您需要使用您想要的初始属性创建一个新的table
local newZombie = {
position = {},
speed = 1,
angle = 0,
}
然后给它一个僵尸该有的所有方法。最简单的方法是使用 metatables。 __index
元方法向 Lua 解释了在未明确设置 field/method 时该怎么做。这让我们 "copy" 僵尸 "class" 进入新实例:
setmetatable(newZombie, {__index = Zombie})
这可以被包装到 Zombie "class" 上的 "constructor" 方法中。由于此构造函数不作用于现有的僵尸对象,因此您应该使用 .
而不是 :
:
来定义和调用它
local Zombie = {}
-- This property is shared between ALL zombies,
-- and changing it will change it for ALL zombies
Zombie.sprite = love.graphics.newImage('sprites/zombie.png')
-- RETURNS a freshly created Zombie instance
function Zombie.create()
local newZombie = {
position = {},
speed = 1,
angle = 0,
sprite = love.graphics.newImage('sprites/zombie.png')
}
return setmetatable(newZombie, {__index = Zombie})
end
-- MODIFIES the zombie that this is called on
function Zombie:move(dt)
local distance = self.speed * dt * 60
self.position.x = self.position.x + math.cos(self.angle) * distance
self.position.y = self.position.y + math.sin(self.angle) * distance
end
function Zombie:setPos(x, y)
self.position.x = x
self.position.y = y
end
-- MODIFIES zombies by adding a freshly created zombie to it
function spawnZombie(zombies)
local newZombie = Zombie.create()
newZombie:setPos(math.random(0, love.graphics.getWidth()), math.random(0, love.graphics.getHeight()))
table.insert(zombieTable, newZombie)
end
-- In update function:
for i, z in ipairs(zombies) do
z:rotate(player1)
z:move(dt)
end
您应该养成在函数中使用 local
变量的习惯,例如 Zombie:move
中的 distance
。全局变量很可能会导致错误,并且还会带来(小的)性能损失,因为与所有人共享变量比将其隐藏要花费更多时间(并且还会使 JIT 优化器的工作更加困难)。
我正在尝试编写游戏。
要点是游戏有玩家,我会生成僵尸,它们会走向玩家。
这些是我的文件:
main.lua
local Player = require("player")
local Zombie = require("zombie")
love.window.setTitle("Shooter")
function love.load()
sprites = {}
sprites.background = love.graphics.newImage('sprites/background.png')
player1 = Player
player1.setPos(300, 300)
zombies = {}
end
function love.update(dt)
player1.move(dt)
player1.rotate()
for i, z in ipairs(zombies) do
z.rotate(player1)
z.move(dt)
end
end
function love.draw()
love.graphics.draw(sprites.background, 0, 0)
love.graphics.draw(player1.sprite, player1.position.x, player1.position.y, player1.angle, nil, nil, player1.sprite:getWidth()/2, player1.sprite:getHeight()/2)
for i,z in ipairs(zombies) do
love.graphics.draw(z.sprite, z.position.x, z.position.y, z.angle, nil, nil, z.sprite:getWidth()/2, z.sprite:getHeight()/2)
love.graphics.printf("order" ..i, 0, 50, love.graphics.getWidth(), "center")
end
end
function distance(player, enemy)
return math.sqrt((player.position.x - enemy.position.x)^2 + (player.position.y - enemy.position.y)^2)
end
function love.keypressed(key, scancode, isrepeat)
if key == "u" then
spawnZombie(zombies)
end
end
zombie.lua
local Zombie = {
position = {},
speed = 1,
angle = 0,
sprite = love.graphics.newImage('sprites/zombie.png')
}
function Zombie.setPos(x, y)
Zombie.position.x = x
Zombie.position.y = y
end
function Zombie.move(dt)
distance = Zombie.speed * dt * 60
Zombie.position.x = Zombie.position.x + math.cos(Zombie.angle) * distance
Zombie.position.y = Zombie.position.y + math.sin(Zombie.angle) * distance
end
function Zombie.rotate(player)
Zombie.angle = math.atan2(player.position.y - Zombie.position.y, player.position.x - Zombie.position.x)
end
function spawnZombie(zombieTable)
zombie = Zombie
zombie.setPos(math.random(0, love.graphics.getWidth()), math.random(0, love.graphics.getHeight()))
table.insert(zombieTable, zombie)
end
return Zombie
最后,player.lua
文件完成。
spawnZombie()
应该创建一个新僵尸并将其插入 zombies
table。 love.draw()
应该遍历 zombies
table 并将它们全部绘制出来。
我遇到了两个问题,很可能相关:
只会生成一个僵尸。
每个生成的僵尸都比最后一个快。
这可能意味着只绘制了一个僵尸(table中的第一个)并且他的速度在love.update()
函数中增加了。如果该假设是正确的,那么问题可能出在 spawnZombie()
函数中。
如何修复我的程序?
Zombie
是你唯一的僵尸。您创建的每个 "new" 僵尸实际上只是它的别名:
zombie = Zombie
不创建副本,但表示 zombie
只是同一对象的另一个名称。
您需要为每个新僵尸创建一个新的 table。您可能想要使用 方法 以便您可以对每个实例使用相同的函数。
一个方法是用:
定义的,并自动获得一个名为self
的不可见参数,它是调用该方法的对象。方法被称为 :move(0.5)
而不是 .move(0.5)
:
function Zombie:move(dt)
local distance = self.speed * dt * 60
self.position.x = self.position.x + math.cos(self.angle) * distance
self.position.y = self.position.y + math.sin(self.angle) * distance
end
要创建一个新的僵尸实例,您需要使用您想要的初始属性创建一个新的table
local newZombie = {
position = {},
speed = 1,
angle = 0,
}
然后给它一个僵尸该有的所有方法。最简单的方法是使用 metatables。 __index
元方法向 Lua 解释了在未明确设置 field/method 时该怎么做。这让我们 "copy" 僵尸 "class" 进入新实例:
setmetatable(newZombie, {__index = Zombie})
这可以被包装到 Zombie "class" 上的 "constructor" 方法中。由于此构造函数不作用于现有的僵尸对象,因此您应该使用 .
而不是 :
:
local Zombie = {}
-- This property is shared between ALL zombies,
-- and changing it will change it for ALL zombies
Zombie.sprite = love.graphics.newImage('sprites/zombie.png')
-- RETURNS a freshly created Zombie instance
function Zombie.create()
local newZombie = {
position = {},
speed = 1,
angle = 0,
sprite = love.graphics.newImage('sprites/zombie.png')
}
return setmetatable(newZombie, {__index = Zombie})
end
-- MODIFIES the zombie that this is called on
function Zombie:move(dt)
local distance = self.speed * dt * 60
self.position.x = self.position.x + math.cos(self.angle) * distance
self.position.y = self.position.y + math.sin(self.angle) * distance
end
function Zombie:setPos(x, y)
self.position.x = x
self.position.y = y
end
-- MODIFIES zombies by adding a freshly created zombie to it
function spawnZombie(zombies)
local newZombie = Zombie.create()
newZombie:setPos(math.random(0, love.graphics.getWidth()), math.random(0, love.graphics.getHeight()))
table.insert(zombieTable, newZombie)
end
-- In update function:
for i, z in ipairs(zombies) do
z:rotate(player1)
z:move(dt)
end
您应该养成在函数中使用 local
变量的习惯,例如 Zombie:move
中的 distance
。全局变量很可能会导致错误,并且还会带来(小的)性能损失,因为与所有人共享变量比将其隐藏要花费更多时间(并且还会使 JIT 优化器的工作更加困难)。