luagame-developmentstate-machinelove2d

lua/love2d - need to understand how pause in PlayState works in love2d breakout game


I'm asking this here because even though there is another board dealing specifically with the course this game is from, hardly anyone ever responds to questions on that board. I'm hoping that those of you familiar with Lua can explain it to me.

The question has to do with with the pause function in a Breakout game that is part of game development course. The issue only concerns two files (I think), both of which are short. The first file is a Lua class called Paddle that generates a paddle for the Breakout game. The second file is part of a state machine called PlayState, which is the state for when the game is being played (obviously).

Here is the code for Paddle.lua:

Paddle = Class{}

function Paddle:init()
    self.x = VIRTUAL_WIDTH / 2 - 32
    self.y = VIRTUAL_HEIGHT - 32
    self.dx = 0
    self.width = 64
    self.height = 16
    self.skin = 1
    self.size = 2
end

function Paddle:update(dt)
    if love.keyboard.isDown('left') then
        self.dx = -PADDLE_SPEED
    elseif love.keyboard.isDown('right') then
        self.dx = PADDLE_SPEED
    else
        self.dx = 0
    end

    if self.dx < 0 then
        self.x = math.max(0, self.x + self.dx * dt)
    else
        self.x = math.min(VIRTUAL_WIDTH - self.width, self.x + self.dx * dt)
    end
end

function Paddle:render()
   love.graphics.draw(gTextures['main'], gFrames['paddles'][self.size + 4 * (self.skin - 1)],
    self.x, self.y)   
end

Here is the code for PlayState.lua:

PlayState = Class{__includes = BaseState}

function PlayState:init()
    self.paddle = Paddle()
    self.paused = false
end

function PlayState:update(dt)
    if self.paused then
        if love.keyboard.wasPressed('space') then
            self.paused = false
            gSounds['pause']:play()
        else
            return
        end
    elseif love.keyboard.wasPressed('space') then
        self.paused = true
        gSounds['pause']:play()
        return
    end

    self.paddle:update(dt)

    if love.keyboard.wasPressed('escape') then
        love.event.quit()
    end
end

function PlayState:render()
    self.paddle:render()

    if self.paused then
        love.graphics.setFont(gFonts['large'])
        love.graphics.printf("PAUSED", 0, VIRTUAL_HEIGHT / 2 - 16, VIRTUAL_WIDTH, 'center')
    end
end

So here's what I understand: the PlayState creates a paddle. self.paused is false. Then PlayState:update starts. If the space bar is hit, the code regarding the space bar doesn't execute. After that, self.paddle:update is called, which checks if the left or right arrow keys are pushed and then sets an x-velocity based on which one is pushed. Once PlayState:update is done, PlayState:render starts, which calls self.paddle:render. self.paddle:render draws the paddle at a new position based on the x-velocity.

Now back to PlayState:update. If the spacebar is hit, self.paused becomes true (and a sound plays). But then self.paddle:update still executes. Now since space was hit, left and right weren't hit, so x-velocity is 0. Then PlayState:render runs again, which calls self.paddle:render, which draws the paddle in the same place as before because there is no x-velocity. Then because self.paused is true, the word PAUSED is drawn on the screen.

Now here's where I'm confused: on the next frame, nothing happens with the paddle if you press left or right. Of course, that's how it's supposed to work, but I don't know why it works. If you press the left key the next time PlayState:update runs, of course self.paused won't change, but self.paddle:update is still called, isn't it? And shouldn't self.paddle:update still register that the left key was pressed? Which would give us an x-velocity, so that when PlayState:render calls self.paddle:render, the paddle would be drawn at the new location based on the x-velocity, even though the word PAUSED will be redrawn on the screen?

I guess what I mean is that I don't understand how setting self.paused to true keeps self.paddle:update from registering a key event and keeps self.paddle:render from drawing the paddle at a new location.


Solution

  • The key is in the first return statement in PlayState:update. If the game is paused, and if the spacebar was not pressed, we reach the else clause, which simply returns from the function before reaching self.paddle:update(dt), so all that paddle math never happens.

    To make it clear, this simplified code should be equivalent:

    function PlayState:update(dt)
        if love.keyboard.wasPressed('space') then
            self.paused = not self.paused
            gSounds['pause']:play()
        end
    
        if not self.paused then
            self.paddle:update(dt)
    
            if love.keyboard.wasPressed('escape') then
                love.event.quit()
            end
        end
    end