UNDER CONSTRUCTION
PICO-8
Pong Tutorial

Step 1: Add a Player Paddle

Let's continue from where we left off with a bouncing ball and add a paddle you can move. First draw yourself up a paddle using Sprite 002 and 018.

Next, let's add some code to draw and move our paddle up and down.


-- ball properties
ball_x = 0  -- x position
ball_y = 0  -- y position
x_speed = 2   -- x speed
y_speed = 1.5 -- y speed

-- player paddle properties
paddle_x = 0
paddle_y = 60
paddle_speed = 3

-- update function
function _update()
  -- update ball position
  ball_x = ball_x + x_speed
  ball_y = ball_y + y_speed
  
  -- left or right side
  if ball_x < 0 or ball_x > 119 then
    -- reverse x direction
    x_speed = x_speed * -1
  end
  
  -- top or bottom side
  if ball_y < 0 or ball_y > 119 then
    -- reverse y direction
    y_speed = y_speed * -1
  end
  
  -- move paddle up and down
  if btn(2) then
    paddle_y = paddle_y - paddle_speed
  end
  
  if btn(3) then
    paddle_y = paddle_y + paddle_speed
  end
end

-- draw function
function _draw()
  -- clear the screen
  cls()
  
  -- draw the ball
  spr(1, ball_x, ball_y)
  
  -- draw the paddle
  spr(2, paddle_x, paddle_y)
  spr(18, paddle_x, paddle_y + 8)
end
        

Now you can move the paddle up and down using the arrow keys!

Step 2: Hit Collision

The ball just passes through the paddle. We will have to check when they are touching to have the ball bounce off the paddle.


-- update function
function _update()
  -- update ball position
  ball_x = ball_x + x_speed
  ball_y = ball_y + y_speed
  
  -- left or right side
  if ball_x < 0 or ball_x > 119 then
    -- reverse x direction
    x_speed = x_speed * -1
  end
  
  -- top or bottom side
  if ball_y < 0 or ball_y > 119 then
    -- reverse y direction
    y_speed = y_speed * -1
  end
  
  -- move player paddle up and down
  if btn(0) then
    paddle_y = paddle_y - paddle_speed
  end
  
  if btn(1) then
    paddle_y = paddle_y + paddle_speed
  end
  
  -- player paddle collision
  if ball_x < paddle_x + 8 and
     ball_x > paddle_x and
     ball_y > paddle_y and 
     ball_y < paddle_y + 16 then
    x_speed = -x_speed
    ball_x = ball_x + x_speed
  end
end

Step 6: Add an Enemy Paddle

Next, we'll add an enemy paddle on the right side of the screen that moves slower than the player's paddle. The enemy paddle will be composed of sprites 4 and 5 stacked vertically.


-- ball properties
ball_x = 0  -- x position
ball_y = 0  -- y position
x_speed = 2   -- x speed
y_speed = 1.5 -- y speed

-- player paddle properties
paddle_x = 10
paddle_y = 60
paddle_speed = 3

-- enemy paddle properties
enemy_paddle_x = 110
enemy_paddle_y = 60
enemy_paddle_speed = 1.5

-- update function
function _update()
  -- update ball position
  ball_x = ball_x + x_speed
  ball_y = ball_y + y_speed
  
  -- left or right side
  if ball_x < 0 or ball_x > 119 then
    -- reverse x direction
    x_speed = x_speed * -1
  end
  
  -- top or bottom side
  if ball_y < 0 or ball_y > 119 then
    -- reverse y direction
    y_speed = y_speed * -1
  end
  
  -- move player paddle up and down
  if btn(0) then
    paddle_y = paddle_y - paddle_speed
  end
  if btn(1) then
    paddle_y = paddle_y + paddle_speed
  end
  
  -- move enemy paddle
  if ball_y > enemy_paddle_y + 7 then
    enemy_paddle_y = enemy_paddle_y + enemy_paddle_speed
  elseif ball_y < enemy_paddle_y then
    enemy_paddle_y = enemy_paddle_y - enemy_paddle_speed
  end
  
  -- player paddle collision
  if ball_x < paddle_x + 8 and ball_y > paddle_y and ball_y < paddle_y + 16 then
    x_speed = -x_speed
  end
  
  -- enemy paddle collision
  if ball_x > enemy_paddle_x - 8 and ball_y > enemy_paddle_y and ball_y < enemy_paddle_y + 16 then
    x_speed = -x_speed
  end
end

-- draw function
function _draw()
  -- clear the screen
  cls()
  
  -- draw the ball
  spr(1, ball_x, ball_y)
  
  -- draw the player paddle
  spr(2, paddle_x, paddle_y)
  spr(3, paddle_x, paddle_y + 8)
  
  -- draw the enemy paddle
  spr(4, enemy_paddle_x, enemy_paddle_y)
  spr(5, enemy_paddle_x, enemy_paddle_y + 8)
end
        

Now you have an enemy paddle that moves slower than the player's paddle!

Step 7: Add Start and Game Over Screens

In this step, we'll add a start screen and a game over screen that lets you play again.


-- ball properties
ball_x = 0  -- x position
ball_y = 0  -- y position
x_speed = 2   -- x speed
y_speed = 1.5 -- y speed

-- player paddle properties
paddle_x = 10
paddle_y = 60
paddle_speed = 3

-- enemy paddle properties
enemy_paddle_x = 110
enemy_paddle_y = 60
enemy_paddle_speed = 1.5

-- game state
game_state = "start"

-- update function
function _update()
  if game_state == "start" then
    if btn(4) then  -- X button
      game_state = "play"
    end
  elseif game_state == "play" then
    -- update ball position
    ball_x = ball_x + x_speed
    ball_y = ball_y + y_speed
    
    -- left or right side
    if ball_x < 0 or ball_x > 119 then
      -- reverse x direction
      x_speed = x_speed * -1
    end
    
    -- top or bottom side
    if ball_y < 0 or ball_y > 119 then
      -- reverse y direction
      y_speed = y_speed * -1
    end
    
    -- move player paddle up and down
    if btn(0) then
      paddle_y = paddle_y - paddle_speed
    end
    if btn(1) then
      paddle_y = paddle_y + paddle_speed
    end
    
    -- move enemy paddle
    if ball_y > enemy_paddle_y + 7 then
      enemy_paddle_y = enemy_paddle_y + enemy_paddle_speed
    elseif ball_y < enemy_paddle_y then
      enemy_paddle_y = enemy_paddle_y - enemy_paddle_speed
    end
    
    -- player paddle collision
    if ball_x < paddle_x + 8 and ball_y > paddle_y and ball_y < paddle_y + 16 then
      x_speed = -x_speed
    end
    
    -- enemy paddle collision
    if ball_x > enemy_paddle_x - 8 and ball_y > enemy_paddle_y and ball_y < enemy_paddle_y + 16 then
      x_speed = -x_speed
    end
  elseif game_state == "gameover" then
    if btn(4) then  -- X button
      game_state = "play"
      ball_x = 0
      ball_y = 0
      x_speed = 2
      y_speed = 1.5
    end
  end
end

-- draw function
function _draw()
  -- clear the screen
  cls()
  
  if game_state == "start" then
    print("Press X to Start", 40, 60, 7)
  elseif game_state == "play" then
    -- draw the ball
    spr(1, ball_x, ball_y)
    
    -- draw the player paddle
    spr(2, paddle_x, paddle_y)
    spr(3, paddle_x, paddle_y + 8)
    
    -- draw the enemy paddle
    spr(4, enemy_paddle_x, enemy_paddle_y)
    spr(5, enemy_paddle_x, enemy_paddle_y + 8)
  elseif game_state == "gameover" then
    print("Game Over!", 50, 50, 7)
    print("Press X to Restart", 35, 60, 7)
  end
end
        

Now you have a start screen and a game over screen that lets you play again!

Step 8: Add a Score and Winning Condition

In this step, we'll add a score and a winning condition where the first player to get 3 points wins.


-- ball properties
ball_x = 0  -- x position
ball_y = 0  -- y position
x_speed = 2   -- x speed
y_speed = 1.5 -- y speed

-- player paddle properties
paddle_x = 10
paddle_y = 60
paddle_speed = 3

-- enemy paddle properties
enemy_paddle_x = 110
enemy_paddle_y = 60
enemy_paddle_speed = 1.5

-- scores
player_score = 0
enemy_score = 0

-- game state
game_state = "start"

-- update function
function _update()
  if game_state == "start" then
    if btn(4) then  -- X button
      game_state = "play"
    end
  elseif game_state == "play" then
    -- update ball position
    ball_x = ball_x + x_speed
    ball_y = ball_y + y_speed
    
    -- left or right side
    if ball_x < 0 then
      player_score += 1
      reset_ball()
    elseif ball_x > 127 then
      enemy_score += 1
      reset_ball()
    end
    
    -- top or bottom side
    if ball_y < 0 or ball_y > 127 then
      -- reverse y direction
      y_speed = y_speed * -1
    end
    
    -- move player paddle up and down
    if btn(0) then
      paddle_y = paddle_y - paddle_speed
    end
    if btn(1) then
      paddle_y = paddle_y + paddle_speed
    end
    
    -- move enemy paddle
    if ball_y > enemy_paddle_y + 7 then
      enemy_paddle_y = enemy_paddle_y + enemy_paddle_speed
    elseif ball_y < enemy_paddle_y then
      enemy_paddle_y = enemy_paddle_y - enemy_paddle_speed
    end
    
    -- player paddle collision
    if ball_x < paddle_x + 8 and ball_y > paddle_y and ball_y < paddle_y + 16 then
      x_speed = -x_speed
    end
    
    -- enemy paddle collision
    if ball_x > enemy_paddle_x - 8 and ball_y > enemy_paddle_y and ball_y < enemy_paddle_y + 16 then
      x_speed = -x_speed
    end
    
    -- check for winning condition
    if player_score == 3 then
      game_state = "player_wins"
    elseif enemy_score == 3 then
      game_state = "enemy_wins"
    end
  elseif game_state == "gameover" then
    if btn(4) then  -- X button
      game_state = "play"
      player_score = 0
      enemy_score = 0
      reset_ball()
    end
  elseif game_state == "player_wins" or game_state == "enemy_wins" then
    if btn(4) then  -- X button
      game_state = "start"
      player_score = 0
      enemy_score = 0
      reset_ball()
    end
  end
end

-- draw function
function _draw()
  -- clear the screen
  cls()
  
  if game_state == "start" then
    print("Press X to Start", 40, 60, 7)
  elseif game_state == "play" then
    -- draw the ball
    spr(1, ball_x, ball_y)
    
    -- draw the player paddle
    spr(2, paddle_x, paddle_y)
    spr(3, paddle_x, paddle_y + 8)
    
    -- draw the enemy paddle
    spr(4, enemy_paddle_x, enemy_paddle_y)
    spr(5, enemy_paddle_x, enemy_paddle_y + 8)
    
    -- draw the scores
    print("Player: " .. player_score, 10, 5, 7)
    print("Enemy: " .. enemy_score, 90, 5, 8)
  elseif game_state == "gameover" then
    print("Game Over!", 50, 50, 7)
    print("Press X to Restart", 35, 60, 7)
  elseif game_state == "player_wins" then
    print("You Win!", 50, 50, 7)
    print("Press X to Restart", 35, 60, 7)
  elseif game_state == "enemy_wins" then
    print("You Lose!", 50, 50, 7)
    print("Press X to Restart", 35, 60, 7)
  end
end

function reset_ball()
  ball_x = 64
  ball_y = 64
  x_speed = 2
  y_speed = 1.5
end
        

Now the game has a score and a winning condition where the first player to get 3 points wins!

Summary

By following these steps, you've built a simple Pong game in Pico-8 with a player paddle, an enemy paddle, start and game over screens, and a scoring system. This tutorial helps new programmers understand how to implement game logic, handle user input, and manage game states in Pico-8.