Professional project
Python code solution and explanation
turtle library
Introduction
Breakout is a classic arcade game that was released in 1976. In this game, the player controls a paddle at the bottom and uses it to deflect a ball upwards to break a wall of bricks. The objective is to clear all the bricks without the ball touching the floor. Despite its age, breakout remains a popular game and is enjoyed by many players today.
Today, we’re going to make breakout in Python, for you to impress your friends and family!
Step Breakdown
Let’s break this game down into smaller steps.
- Make game window
- Display all bricks
- Paddle movement
- Ball movement
- Detect collision with walls and bricks
- Scoreboard
With this overview, we broadly know what to do and we can check each item while making our game.
Solution
We’ll have 5 different files, main.py, bricks.py, paddle.py, ball.py, and scoreboard.py. The last 4 files will have their own class and functions, while the main file will execute all the code.
main.py
from turtle import Screen
from paddle import Paddle
from bricks import Bricks
from ball import Ball
from scoreboard import Scoreboard
Now we can make a screen. You can choose your own customization. Make sure to turn screen.tracer()
to 0, so that there’s no delay when the game runs.
screen = Screen()
screen.bgcolor("black")
screen.setup(width=800, height=600)
screen.title("Breakout")
screen.tracer(0)
Set each class to an object. Right now we’re just going to code and name all the functions, and later we will make them.
bricks = Bricks()
paddle = Paddle()
ball = Ball()
scoreboard = Scoreboard()
When the arrow keys are pressed, execute its corresponding function.
screen.listen()
screen.onkey(paddle.go_right, "Right")
screen.onkeypress(paddle.go_right, "Right")
screen.onkey(paddle.go_left, "Left")
screen.onkeypress(paddle.go_left, "Left")
While not game_over
, update the screen and move the ball.
game_over = False
while not game_over:
screen.update()
ball.move()
If the y coordinate of the ball touches the floor, the game is over and display the message.
# Detect collision with floor (game over)
if ball.ycor() < -280:
game_over = True
scoreboard.game_over()
However, if the x coordinate of the ball touches the side walls, bounce the ball on x-axis.
# Detect collision with sides
if ball.xcor() > 380 or ball.xcor() < -380:
ball.bounce_x()
If the y coordinate of the ball touches the ceiling, bounce the ball on y-axis.
# Detect collision with ceiling
if ball.ycor() > 280:
ball.bounce_y()
If the ball’s x and y coordinates are close to the paddle, bounce the ball on y-axis.
# Detect collision with paddle
if ball.distance(paddle) < 120 and ball.ycor() < -235:
ball.bounce_y()
For each brick in all_bricks, if the x and y coordinates of the ball is close to the brick, bounce the ball on the y-axis, and remove that brick from all_bricks.
# Detect collision with brick
for brick in bricks.all_bricks:
if ball.distance(brick) < 70 and ball.ycor() > brick.position()[1] - 30:
ball.bounce_y()
bricks.remove_brick(brick)
If all_bricks is empty, or there are no bricks left, the game is over and print a message.
# Check if no bricks left (winner)
if not bricks.all_bricks:
game_over = True
scoreboard.you_win()
bricks.py
We can predefine the bricks positions. These are the coordinates I found best.
from turtle import Turtle
BRICKS_POSITIONS = [(-330, 150), (-195, 150), (-60, 150), (75, 150), (210, 150), (345, 150),
(-330, 110), (-195, 110), (-60, 110), (75, 110), (210, 110), (345, 110),
(-330, 70), (-195, 70), (-60, 70), (75, 70), (210, 70), (345, 70),
(-330, 30), (-195, 30), (-60, 30), (75, 30), (210, 30), (345, 30),
(-330, -10), (-195, -10), (-60, -10), (75, -10), (210, -10), (345, -10),
(-330, -50), (-195, -50), (-60, -50), (75, -50), (210, -50), (345, -50)]
All the bricks will be saved into self.all_bricks
. We can then call self.create_bricks()
.
class Bricks:
def __init__(self):
self.all_bricks = []
self.create_bricks()
For create_bricks()
, for position in BRICKS_POSITIONS
, we can call self.add_brick(position)
def create_bricks(self):
for position in BRICKS_POSITIONS:
self.add_brick(position)
For add_brick(position)
, it will make a new_brick
and go to the position specified. Then it will append new_brick
to self.all_bricks
.
def add_brick(self, position):
new_brick = Turtle("square")
new_brick.color("brown")
new_brick.shapesize(stretch_wid=1.5, stretch_len=6.4)
new_brick.penup()
new_brick.goto(position)
self.all_bricks.append(new_brick)
For remove_brick(brick)
, we can remove the brick from the list but that won’t get rid of it from the screen. We can send the brick outside of the screen.
def remove_brick(self, brick):
self.all_bricks.remove(brick)
brick.goto(1000, 1000)
ball.py
Our Ball()
class will inherit from the Turtle
library. The ball will go right on top of the paddle to start off. self.x_move
and self.y_move
will be used later.
from turtle import Turtle
class Ball(Turtle):
def __init__(self):
super().__init__()
self.color("white")
self.shape("circle")
self.penup()
self.x_move = 1
self.y_move = 1
self.goto(0, -225)
For move(), new_x will equal the current x coordinate + self.x_move, and new_y will equal the current y coordinate + self.y_move. Then we can send the ball to this new x and y coordinate.
def move(self):
new_x = self.xcor() + self.x_move
new_y = self.ycor() + self.y_move
self.goto((new_x, new_y))
For bounce_x
, we will multiply x_move
by -1. Same with bounce_y
. The next time move()
runs, the new_x
or new_y
will be subtracted.
def bounce_y(self):
self.y_move *= -1
def bounce_x(self):
self.x_move *= -1
scoreboard.py
I’m going to save the font information to a variable, to make it easier to reference.
from turtle import Turtle
FONT = ("Arial", 50, "italic")
Our Scoreboard()
class will also inherit from the Turtle
library. Remember to hide the turtle.
class Scoreboard(Turtle):
def __init__(self):
super().__init__()
self.score = 0
self.color("white")
self.penup()
self.goto(0, 260)
self.hideturtle()
For you_win(), it will go to the center of the screen and write “you win”.
def you_win(self):
self.goto(0, 0)
self.write("YOU WIN!!!", align="center", font=FONT)
For game_over(), it will go to the center of the screen and write “game over”.
def game_over(self):
self.goto(0, 0)
self.write("GAME OVER", align="center", font=FONT)
That sums up our game.
Gameplay
Final Code
To view my full code, please visit my GitHub repository:
https://github.com/Gursehaj-Singh/breakout-game
main.py
from turtle import Screen
from paddle import Paddle
from bricks import Bricks
from ball import Ball
from scoreboard import Scoreboard
screen = Screen()
screen.bgcolor("black")
screen.setup(width=800, height=600)
screen.title("Breakout")
screen.tracer(0)
bricks = Bricks()
paddle = Paddle()
ball = Ball()
scoreboard = Scoreboard()
screen.listen()
screen.onkey(paddle.go_right, "Right")
screen.onkeypress(paddle.go_right, "Right")
screen.onkey(paddle.go_left, "Left")
screen.onkeypress(paddle.go_left, "Left")
game_over = False
while not game_over:
screen.update()
ball.move()
# Detect collision with floor (game over)
if ball.ycor() < -280:
game_over = True
scoreboard.game_over()
# Detect collision with sides
if ball.xcor() > 380 or ball.xcor() < -380:
ball.bounce_x()
# Detect collision with ceiling
if ball.ycor() > 280:
ball.bounce_y()
# Detect collision with paddle
if ball.distance(paddle) < 120 and ball.ycor() < -235:
ball.bounce_y()
# Detect collision with brick
for brick in bricks.all_bricks:
if ball.distance(brick) < 70 and ball.ycor() > brick.position()[1] - 30:
ball.bounce_y()
bricks.remove_brick(brick)
# Check if no bricks left (winner)
if not bricks.all_bricks:
game_over = True
scoreboard.you_win()
screen.exitonclick()
bricks.py
from turtle import Turtle
BRICKS_POSITIONS = [(-330, 150), (-195, 150), (-60, 150), (75, 150), (210, 150), (345, 150),
(-330, 110), (-195, 110), (-60, 110), (75, 110), (210, 110), (345, 110),
(-330, 70), (-195, 70), (-60, 70), (75, 70), (210, 70), (345, 70),
(-330, 30), (-195, 30), (-60, 30), (75, 30), (210, 30), (345, 30),
(-330, -10), (-195, -10), (-60, -10), (75, -10), (210, -10), (345, -10),
(-330, -50), (-195, -50), (-60, -50), (75, -50), (210, -50), (345, -50)]
class Bricks:
def __init__(self):
self.all_bricks = []
self.create_bricks()
def create_bricks(self):
for position in BRICKS_POSITIONS:
self.add_brick(position)
def add_brick(self, position):
new_brick = Turtle("square")
new_brick.color("brown")
new_brick.shapesize(stretch_wid=1.5, stretch_len=6.4)
new_brick.penup()
new_brick.goto(position)
self.all_bricks.append(new_brick)
def remove_brick(self, brick):
self.all_bricks.remove(brick)
brick.goto(1000, 1000)
paddle.py
from turtle import Turtle
class Paddle(Turtle):
def __init__(self):
super().__init__()
self.shape("square")
self.color("white")
self.shapesize(stretch_wid=1, stretch_len=10)
self.penup()
self.goto(0, -250)
def go_right(self):
new_x = self.xcor() + 40
self.goto(new_x, self.ycor())
def go_left(self):
new_x = self.xcor() - 40
self.goto(new_x, self.ycor())
ball.py
from turtle import Turtle
class Ball(Turtle):
def __init__(self):
super().__init__()
self.color("white")
self.shape("circle")
self.penup()
self.x_move = 1
self.y_move = 1
self.goto(0, -225)
def move(self):
new_x = self.xcor() + self.x_move
new_y = self.ycor() + self.y_move
self.goto((new_x, new_y))
def bounce_y(self):
self.y_move *= -1
def bounce_x(self):
self.x_move *= -1
scoreboard.py
from turtle import Turtle
FONT = ("Arial", 50, "italic")
class Scoreboard(Turtle):
def __init__(self):
super().__init__()
self.score = 0
self.color("white")
self.penup()
self.goto(0, 260)
self.hideturtle()
def you_win(self):
self.goto(0, 0)
self.write("YOU WIN!!!", align="center", font=FONT)
def game_over(self):
self.goto(0, 0)
self.write("GAME OVER", align="center", font=FONT)
Further Steps
Now that we’ve built the main functionality of breakout, you may want to include other things to enhance the gameplay. This could include:
- Power-ups
- Obstacles, such as rocks or barriers
- Levels with increasing difficulty
- Multiplayer mode so 2 people can play on the same screen
Hope you enjoyed.