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

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