Book Free Trial

Curriculum

Turtle: Pong Game

Build Pong in Python with Turtle Graphics

Subject: ProgrammingCourse: Intro To Python With TurtleAges: Junior, Intermediate, Senior

Theory

Overview

In this project, we built a simple version of Pong, one of the earliest video games, using Python's built-in turtle module. It's an excellent introduction to animation, game loops, event handling, and collision detection.

This project helps beginners understand how a real-time game can be created from scratch—no external libraries needed.

What You'll Learn

  • Setting up a basic game screen using turtle.Screen()
  • Drawing and moving paddles with keyboard input
  • Animating a bouncing ball
  • Detecting collisions with walls and paddles
  • Keeping and displaying a live score
  • Using variables and conditionals to control game logic

How We Coded It

We started by importing the turtle module and creating a window with a black background and a title. Then, we created two paddle objects and a ball:

paddle_a = turtle.Turtle()
paddle_b = turtle.Turtle()
ball = turtle.Turtle()

Each paddle can be moved up and down using the W/S keys (Player A) and Arrow Up/Down keys (Player B). The movement is done using onkeypress() bindings.

To animate the ball, we used a while True game loop, where the ball continuously updates its position based on its dx and dy values. When it hits the top or bottom walls, it bounces back by reversing its vertical direction.

Collision detection is handled using simple boundary checks:

if (340 < ball.xcor() < 350) and (paddle_b.ycor() - 50 < ball.ycor() < paddle_b.ycor() + 50):
    # Bounce off right paddle

Scores are kept in two variables, score_a and score_b, and displayed at the top of the screen using another turtle object.

We also introduced a speed multiplier to make the game more exciting—the ball speeds up slightly with every bounce.

Possible Extensions

If you're interested in taking it further, you could:

  • Add sound effects
  • Create a main menu or game over screen
  • Add difficulty levels or a countdown timer
  • Turn it into a two-player online game using sockets
__wf_reserved_inherit

Problems

Full Python Code

import turtle

# Set up the screen
wn = turtle.Screen()
wn.title("Pong")
wn.bgcolor("black")
wn.setup(width=800, height=600)

# Score variables
score_a = 0
score_b = 0

# Initial speed settings
initial_speed = 4
speed_multiplier = 1.05

# Paddle A
paddle_a = turtle.Turtle()
paddle_a.speed(0)
paddle_a.shape("square")
paddle_a.color("white")
paddle_a.shapesize(stretch_wid=6, stretch_len=1)
paddle_a.penup()
paddle_a.goto(-350, 0)

# Paddle B
paddle_b = turtle.Turtle()
paddle_b.speed(0)
paddle_b.shape("square")
paddle_b.color("white")
paddle_b.shapesize(stretch_wid=6, stretch_len=1)
paddle_b.penup()
paddle_b.goto(350, 0)

# Ball
ball = turtle.Turtle()
ball.speed(0)
ball.shape("square")
ball.color("white")
ball.penup()
ball.goto(0, 0)
ball.dx = initial_speed
ball.dy = initial_speed

# Score display
score_display = turtle.Turtle()
score_display.speed(0)
score_display.color("white")
score_display.penup()
score_display.hideturtle()
score_display.goto(0, 260)
score_display.write("Player A: 0    Player B: 0", align="center", font=("Courier", 24, "normal"))

# Function to update score
def update_score():
    score_display.clear()
    score_display.write(f"Player A: {score_a}    Player B: {score_b}", align="center", font=("Courier", 24, "normal"))

# Paddle movement functions
def paddle_a_up():
    y = paddle_a.ycor()
    if y < 250:
        paddle_a.sety(y + 20)

def paddle_a_down():
    y = paddle_a.ycor()
    if y > -250:
        paddle_a.sety(y - 20)

def paddle_b_up():
    y = paddle_b.ycor()
    if y < 250:
        paddle_b.sety(y + 20)

def paddle_b_down():
    y = paddle_b.ycor()
    if y > -250:
        paddle_b.sety(y - 20)

# Keyboard bindings
wn.listen()
wn.onkeypress(paddle_a_up, "w")
wn.onkeypress(paddle_a_down, "s")
wn.onkeypress(paddle_b_up, "Up")
wn.onkeypress(paddle_b_down, "Down")

# Main game loop
while True:
    wn.update()

    # Move the ball
    ball.setx(ball.xcor() + ball.dx)
    ball.sety(ball.ycor() + ball.dy)

    # Top and bottom wall collision
    if ball.ycor() > 290:
        ball.sety(290)
        ball.dy *= -1
        ball.dx *= speed_multiplier
        ball.dy *= speed_multiplier

    if ball.ycor() < -290:
        ball.sety(-290)
        ball.dy *= -1
        ball.dx *= speed_multiplier
        ball.dy *= speed_multiplier

    # Right wall — Player A scores
    if ball.xcor() > 390:
        ball.goto(0, 0)
        ball.dx = -initial_speed
        ball.dy = initial_speed
        score_a += 1
        update_score()

    # Left wall — Player B scores
    if ball.xcor() < -390:
        ball.goto(0, 0)
        ball.dx = initial_speed
        ball.dy = initial_speed
        score_b += 1
        update_score()

    # Paddle collisions
    if (340 < ball.xcor() < 350) and (paddle_b.ycor() - 50 < ball.ycor() < paddle_b.ycor() + 50):
        ball.setx(340)
        ball.dx *= -1
        ball.dx *= speed_multiplier
        ball.dy *= speed_multiplier

    if (-350 < ball.xcor() < -340) and (paddle_a.ycor() - 50 < ball.ycor() < paddle_a.ycor() + 50):
        ball.setx(-340)
        ball.dx *= -1
        ball.dx *= speed_multiplier
        ball.dy *= speed_multiplier