Lua - проблемы итерации по таблице - PullRequest
0 голосов
/ 22 сентября 2018

Я пытаюсь запрограммировать игру.

Суть в том, что в игре есть игрок, и я буду вызывать зомби, которые будут идти к игроку.

Это мои файлы:

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.love.draw() должен перебрать таблицу zombies и нарисовать их все.

Есть две проблемы, с которыми я сталкиваюсь, очень вероятно связанные:

  1. Только один зомбикогда-либо появляется.

  2. Каждый порожденный зомби быстрее, чем последний.

Это, вероятно, означает, что только один зомби (первый вТаблица) когда-либо рисуется, и его скорость увеличивается с помощью функции love.update().Если это предположение верно, то проблема, вероятно, заключается в функции spawnZombie().

Как исправить программу?

1 Ответ

0 голосов
/ 22 сентября 2018

Zombie - ваш единственный зомби.Каждый «новый» зомби, которого вы создаете, на самом деле является просто псевдонимом для него:

zombie = Zombie не создает копию, но говорит, что zombie - это просто другое имя для того же объекта.

Вам нужно создать новую таблицу для каждого нового зомби.Возможно, вы захотите использовать методы , чтобы вы могли использовать одни и те же функции для каждого экземпляра.

Метод определяется с помощью : и автоматически получает невидимый параметр с именем 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

Чтобы создать новый экземпляр зомби, вам нужно создать новую таблицу с начальными свойствами, которые вы хотите

local newZombie = {
    position = {},
    speed = 1,
    angle = 0,
}

и затем дайте ему все методы, которые должен иметь Зомби.Кратчайший способ сделать это - использовать metatables .Метаметод __index объясняет Lua, что делать, когда поле / метод запрашивается, но это не было явно установлено.Это позволяет нам «копировать» «класс» Zombie на новые экземпляры:

setmetatable(newZombie, {__index = Zombie})

Это можно заключить в метод «конструктор» в «классе» Zombie.Поскольку этот конструктор не действует на существующий объект-зомби, вы должны определить и вызвать его с помощью . вместо ::

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 переменных в ваших функциях, таких как distance в Zombie:move.Глобальные переменные могут вызывать ошибки, а также приводить к (небольшому) снижению производительности, поскольку совместное использование переменной для всех занимает больше времени, чем ее скрытие (а также усложняет работу оптимизатора JIT).

...