为什么我的道具没有出现在我的 LOVE2D 游戏中?

Why is my powerup not showing up in my LOVE2D game?

我目前正在制作名为 PlayBall 的 Pong 重制版,这是一个色彩丰富的版本,具有增强功能、模式和新增功能。我现在处于 Alpha 2.0(Powerup 概念),我想制作我的第一个名为 AddBall 的 powerup。

这个道具的作用是,当球与其碰撞时,会生成一个新球。

我在AddBall.lua中设置了代码:

AddBall = Class{}

local spawner = math.random(10, 20)

function AddBall:init(x, y)
    self.x = x
    self.y = y
    self.width = 8
    self.height = 8
    
    self.timer = 0
    
    self.inPlay = false
end

function AddBall:collides(ball)
    -- first, check to see if the left edge of either is farther to the right
    -- than the right edge of the other
    if self.x > ball.x + ball.width or ball.x > self.x + self.width then
        return false
    end

    -- then check to see if the bottom edge of either is higher than the top
    -- edge of the other
    if self.y > ball.y + ball.height or ball.y > self.y + self.height then
        return false
    end 

    -- if the above aren't true, they're overlapping
    return true
end

function AddBall:update(dt)
    self.timer = self.timer + dt
    
    if self.timer > spawner then
        self.inPlay = true
    end
    
    if self.inPlay then
        self:render()
    end
end

function AddBall:render()
    love.graphics.draw(textures['powerups'], frames['powerups'][1], self.x, self.y)
end

function AddBall:reset()
    self.timer = 0
    self.inPlay = false
    spawner = math.random(10, 20)
end

这是我做的最好的。然后我在 main.lua 中分配了一大堆东西来加载道具和第二个球:

--[[
    Called just once at the beginning of the game; used to set up
    game objects, variables, etc. and prepare the game world.
]]
function love.load()
    -- set love's default filter to "nearest-neighbor", which essentially
    -- means there will be no filtering of pixels (blurriness), which is
    -- important for a nice crisp, 2D look
    love.graphics.setDefaultFilter('nearest', 'nearest')

    -- set the title of our application window
    love.window.setTitle('PlayBall')

    -- seed the RNG so that calls to random are always random
    math.randomseed(os.time())

    -- initialize our nice-looking retro text fonts
    smallFont = love.graphics.newFont('font.ttf', 8)
    largeFont = love.graphics.newFont('font.ttf', 16)
    scoreFont = love.graphics.newFont('font.ttf', 32)
    love.graphics.setFont(smallFont)

    -- set up our sound effects; later, we can just index this table and
    -- call each entry's `play` method
    sounds = {
        ['paddle_hit'] = love.audio.newSource('sounds/paddle_hit.wav', 'static'),
        ['score'] = love.audio.newSource('sounds/score.wav', 'static'),
        ['wall_hit'] = love.audio.newSource('sounds/wall_hit.wav', 'static')
    }
    
    textures = {
        ['powerups'] = love.graphics.newImage('graphics/powerups.png')
    }
    
    frames = {
        ['powerups'] = GenerateQuadsPowerups(textures['powerups'])
    }
    
    -- initialize our virtual resolution, which will be rendered within our
    -- actual window no matter its dimensions
    push:setupScreen(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT, {
        fullscreen = false,
        resizable = true,
        vsync = true
    })

    -- initialize our player paddles; make them global so that they can be
    -- detected by other functions and modules
    player1 = Paddle(10, 30, 5, 20)
    player2 = Paddle(VIRTUAL_WIDTH - 10, VIRTUAL_HEIGHT - 30, 5, 20)

    -- place a ball in the middle of the screen
    ball1 = Ball(VIRTUAL_WIDTH / 2 - 2, VIRTUAL_HEIGHT / 2 - 2, 4, 4, 1)
    ball2 = Ball(ball1.x, ball1.y, 4, 4, 2)
    
    powerup1 = AddBall(math.random(20, VIRTUAL_WIDTH - 20), math.random(0, VIRTUAL_HEIGHT - 8))

    -- set up in play to ensure it is in game
    ball1.inPlay = true

    -- initialize score variables
    player1Score = 0
    player2Score = 0

    -- either going to be 1 or 2; whomever is scored on gets to serve the
    -- following turn
    servingPlayer = 1

    -- player who won the game; not set to a proper value until we reach
    -- that state in the game
    winningPlayer = 0

    -- the state of our game; can be any of the following:
    -- 1. 'start' (the beginning of the game, before first serve)
    -- 2. 'serve' (waiting on a key press to serve the ball)
    -- 3. 'play' (the ball is in play, bouncing between paddles)
    -- 4. 'done' (the game is over, with a victor, ready for restart)
    gameState = 'start'
end

然后游戏更新:

--[[
    Called every frame, passing in `dt` since the last frame. `dt`
    is short for `deltaTime` and is measured in seconds. Multiplying
    this by any changes we wish to make in our game will allow our
    game to perform consistently across all hardware; otherwise, any
    changes we make will be applied as fast as possible and will vary
    across system hardware.
]]
function love.update(dt)
    if gameState == 'serve' then
        -- before switching to play, initialize ball's velocity based
        -- on player who last scored
        ball1.dy = math.random(-50, 50)
        if servingPlayer == 1 then
            ball1.dx = math.random(140, 200)
        else
            ball1.dx = -math.random(140, 200)
        end
    elseif gameState == 'play' then
        -- detect ball collision with paddles, reversing dx if true and
        -- slightly increasing it, then altering the dy based on the position
        -- at which it collided, then playing a sound effect
        if ball1:collides(player1) then
            ball1.dx = -ball1.dx * 1.03
            ball1.x = player1.x + 5

            -- keep velocity going in the same direction, but randomize it
            if ball1.dy < 0 then
                ball1.dy = -math.random(10, 150)
            else
                ball1.dy = math.random(10, 150)
            end

            sounds['paddle_hit']:play()
        end
        if ball1:collides(player2) then
            ball1.dx = -ball1.dx * 1.03
            ball1.x = player2.x - 4

            -- keep velocity going in the same direction, but randomize it
            if ball1.dy < 0 then
                ball1.dy = -math.random(10, 150)
            else
                ball1.dy = math.random(10, 150)
            end

            sounds['paddle_hit']:play()
        end
        if ball2:collides(player1) then
            ball2.dx = -ball2.dx * 1.03
            ball2.x = player1.x + 5

            -- keep velocity going in the same direction, but randomize it
            if ball2.dy < 0 then
                ball2.dy = -math.random(10, 150)
            else
                ball2.dy = math.random(10, 150)
            end

            sounds['paddle_hit']:play()
        end
        if ball2:collides(player2) then
            ball2.dx = -ball2.dx * 1.03
            ball2.x = player2.x - 4

            -- keep velocity going in the same direction, but randomize it
            if ball2.dy < 0 then
                ball2.dy = -math.random(10, 150)
            else
                ball2.dy = math.random(10, 150)
            end

            sounds['paddle_hit']:play()
        end

        -- detect upper and lower screen boundary collision, playing a sound
        -- effect and reversing dy if true
        if ball1.y <= 0 then
            ball1.y = 0
            ball1.dy = -ball1.dy
            sounds['wall_hit']:play()
        end

        -- -4 to account for the ball's size
        if ball1.y >= VIRTUAL_HEIGHT - 4 then
            ball1.y = VIRTUAL_HEIGHT - 4
            ball1.dy = -ball1.dy
            sounds['wall_hit']:play()
        end
        
        -- detect upper and lower screen boundary collision, playing a sound
        -- effect and reversing dy if true
        if ball2.y <= 0 then
            ball2.y = 0
            ball2.dy = -ball2.dy
            sounds['wall_hit']:play()
        end

        -- -4 to account for the ball's size
        if ball2.y >= VIRTUAL_HEIGHT - 4 then
            ball2.y = VIRTUAL_HEIGHT - 4
            ball2.dy = -ball2.dy
            sounds['wall_hit']:play()
        end

        -- if we reach the left edge of the screen, go back to serve
        -- and update the score and serving player
        if ball1.x < 0 then
            servingPlayer = 1
            player2Score = player2Score + 1
            sounds['score']:play()

            -- if we've reached a score of 10, the game is over; set the
            -- state to done so we can show the victory message
            if player2Score == 10 then
                winningPlayer = 2
                gameState = 'done'
            else
                gameState = 'serve'
                -- places the ball in the middle of the screen, no velocity
                ball1:reset()
            end
        end

        -- if we reach the right edge of the screen, go back to serve
        -- and update the score and serving player
        if ball1.x > VIRTUAL_WIDTH then
            servingPlayer = 2
            player1Score = player1Score + 1
            sounds['score']:play()

            -- if we've reached a score of 10, the game is over; set the
            -- state to done so we can show the victory message
            if player1Score == 10 then
                winningPlayer = 1
                gameState = 'done'
            else
                gameState = 'serve'
                -- places the ball in the middle of the screen, no velocity
                ball1:reset()
            end
        end
        
        -- check if ball powerup is added
        if powerup1:collides(ball1) then
            ball2.inPlay = true
            ball2:update(dt)
            powerup1:reset()
        end
        
        -- ball 2 is resetted when it hits the edge
        if ball2.x < 0 or ball2.x > VIRTUAL_WIDTH then
            ball2.inPlay = false
        end
    end

    --
    -- paddles can move no matter what state we're in
    --
    -- player 1
    if love.keyboard.isDown('w') then
        player1.dy = -PADDLE_SPEED
    elseif love.keyboard.isDown('s') then
        player1.dy = PADDLE_SPEED
    else
        player1.dy = 0
    end

    -- player 2
    if aiMode == true then
        player2.y = ball1.y
    elseif aiMode == false then
        if love.keyboard.isDown('up') then
            player2.dy = -PADDLE_SPEED
        elseif love.keyboard.isDown('down') then
            player2.dy = PADDLE_SPEED
        else
            player2.dy = 0
        end
    end

    -- update our ball based on its DX and DY only if we're in play state;
    -- scale the velocity by dt so movement is framerate-independent
    if gameState == 'play' then
        ball1:update(dt)
    end

    player1:update(dt)
    player2:update(dt)
    powerup1:update(dt)
end

我的问题是加电不会生成,使加电概念不完整。不知道是我渲染出了问题,还是时机不对。

我的猜测是我在 Ball.lua:

上出了问题
Ball = Class{}

function Ball:init(x, y, width, height, num)
    self.x = x
    self.y = y
    self.width = width
    self.height = height
    self.count = num

    -- these variables are for keeping track of our velocity on both the
    -- X and Y axis, since the ball can move in two dimensions
    self.dy = 0
    self.dx = 0
    
    self.inPlay = false
end

--[[
    Expects a paddle as an argument and returns true or false, depending
    on whether their rectangles overlap.
]]
function Ball:collides(paddle)
    -- first, check to see if the left edge of either is farther to the right
    -- than the right edge of the other
    if self.x > paddle.x + paddle.width or paddle.x > self.x + self.width then
        return false
    end

    -- then check to see if the bottom edge of either is higher than the top
    -- edge of the other
    if self.y > paddle.y + paddle.height or paddle.y > self.y + self.height then
        return false
    end 

    -- if the above aren't true, they're overlapping
    return true
end

--[[
    Places the ball in the middle of the screen, with no movement.
]]
function Ball:reset()
    self.x = VIRTUAL_WIDTH / 2 - 2
    self.y = VIRTUAL_HEIGHT / 2 - 2
    self.dx = 0
    self.dy = 0
end

function Ball:update(dt)
    self.x = self.x + self.dx * dt
    self.y = self.y + self.dy * dt
end

function Ball:render()
    if self.inPlay then
        love.graphics.setFont(smallFont)
        love.graphics.setColor(0/255, 0/255, 0/255, 255/255)
        love.graphics.printf(tostring(self.count), 2, self.y - 8, VIRTUAL_WIDTH, 'center')
        love.graphics.rectangle('fill', self.x + 2, self.y + 2, self.width, self.height)
        love.graphics.setColor(255/255, 255/255, 255/255, 255/255)
        love.graphics.printf(tostring(self.count), 0, self.y - 10, VIRTUAL_WIDTH, 'center')
        love.graphics.rectangle('fill', self.x, self.y, self.width, self.height)
    end
end

或在 AddBall.lua 中,但我的道具不会生成。你能告诉我为什么吗?

我会 post GitHub 中的东西,如果你想仔细看的话,我的 AddBall powerup 是绿色十字。

我认为这是因为你只在 powerup 与 ball1 发生碰撞时才更新 ball2。由于您在更新方法中渲染了球,因此您只能在它更新时看到它(它没有更新)

我建议你这样做:

if ball2.inPlay then
     ball2:update(dt)
end

你说你的道具没有出现。这可能是因为您没有出于该推理而在 love.draw 中调用 powerup1:render()。尝试更新生成道具和球的概念,因为您需要以某种方式渲染它。

试试这样:

if powerup1.inPlay then
    powerup1:render()
end