Login

Please fill in your details to login.





python asteroids

Build a classic game of asteroids using Python Turtle

image
Today, you are going to build a fully working Asteroids game using Python 3. For this tutorial, you will be using Thonny, which is a fantastic environment for writing and running Python code. We will be using the built-in
turtle
module to draw the graphics. Make sure you read the introduction to each code block before you copy and paste it into the IDE.

image
Classic Asteroids... but you can't play it here...

0
Get ready to code!

1
Open up Thonny
2
You should get a blank script editor and output window. If not, create a new file from the File menu.
3
Organise your workspace.

1
Setting up the Game Screen

Before we can draw any shapes or move any pieces, we need a blank canvas to work with. This step is designed to initialise the game window, set its size, give it a background colour, and title it. We also use a special command called
tracer(0)
. By default, the
turtle
module animates every single thing it draws. For a fast-paced game, this would look very jerky. By setting the tracer to zero, we turn off these automatic updates, allowing us to manually refresh the screen later on for perfectly smooth gameplay.

import turtle
import time
import random
import math
wn = turtle.Screen()
wn.title("Asteroids  -  The Computing Café")
wn.bgcolor("black")
wn.setup(width=600, height=600)
wn.tracer(0)

# Next: 2. Creating the Spaceship


2
Creating the Spaceship

Now we create the player's spaceship. In the
turtle
module, we can register our own custom shapes. We will define a simple triangle for our ship. We then create a new turtle object and assign it this new shape. We will also give it a heading (the direction it is facing) and variables to track its movement speed (
dx
and
dy
).

ship_shape = ((-10, -10), (0, 20), (10, -10), (-10, -10))
wn.register_shape("ship", ship_shape)
player = turtle.Turtle()
player.speed(0)
player.shape("ship")
player.color("blue")
player.penup()
player.goto(0, 0)
player.setheading(90)
player.dx = 0
player.dy = 0

# Next: 3. Spawning the Asteroids


3
Spawning the Asteroids

What's a game of Asteroids without asteroids? We will use a loop to create several of them. Each asteroid is a turtle with a "circle" shape. We'll give each one a random starting position and a random direction and speed of travel. To keep track of all of them, we'll store them in a list called
asteroids
.

asteroids = []
for _ in range(10):
    asteroid = turtle.Turtle()
    asteroid.speed(0)
    asteroid.shape("circle")
    asteroid.color("grey")
    asteroid.penup()
    asteroid.goto(random.randint(-290, 290), random.randint(-290, 290))
    asteroid.dx = random.uniform(-1, 1)
    asteroid.dy = random.uniform(-1, 1)
    asteroids.append(asteroid)

# Next: 4. Preparing the Ammunition


4
Preparing the Ammunition

Our ship needs to be able to shoot! We will create an empty list to hold all the laser bullets that the player fires. Unlike the player and the asteroids, which exist at the start of the game, bullets will be created one by one every time the player presses the fire key. This list will help us manage all of them at once.

bullets = []

# Next: 5. The Scoreboard


5
The Scoreboard

We need a way to show the player their score and other messages. To do this, we create another turtle object. We don't want to see this turtle's shape, only the text it writes. We will hide the turtle, move it to the top of the screen, and use it to display the starting score.

score = 0
pen = turtle.Turtle()
pen.speed(0)
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0, 260)
pen.write("Score: 0", align="center", font=("Courier", 24, "normal"))

# Next: 6. Adding Player Controls


6
Adding Player Controls

You need to be able to interact with the game! We define four functions: one to turn left, one to turn right, one to apply thrust to move forward, and one to fire a bullet. Applying thrust uses a little bit of maths to convert the ship's angle into horizontal (
dx
) and vertical (
dy
) speed. Firing creates a new bullet turtle and gives it a high speed in the direction the ship is facing. Finally, we tell the computer to "listen" for keyboard inputs.

def turn_left():
    player.left(20)
def turn_right():
    player.right(20)
def increase_thrust():
    angle = math.radians(player.heading())
    player.dx += math.cos(angle) * 0.2
    player.dy += math.sin(angle) * 0.2
def fire_bullet():
    bullet = turtle.Turtle()
    bullet.speed(0)
    bullet.shape("circle")
    bullet.color("yellow")
    bullet.shapesize(stretch_wid=0.2, stretch_len=0.2)
    bullet.penup()
    bullet.goto(player.xcor(), player.ycor())
    bullet.setheading(player.heading())
    bullet.dx = math.cos(math.radians(bullet.heading())) * 5
    bullet.dy = math.sin(math.radians(bullet.heading())) * 5
    bullets.append(bullet)
wn.listen()
wn.onkeypress(turn_left, "Left")
wn.onkeypress(turn_right, "Right")
wn.onkeypress(increase_thrust, "Up")
wn.onkeypress(fire_bullet, "space")

# Next: 7. The Main Game Loop & Wrapping Space


7
The Main Game Loop & Wrapping Space

This is the engine of your game. The
while True:
loop will run continuously forever. Inside this loop, we update the screen, add a tiny pause (
time.sleep
) so the game runs at a playable speed, and move the player, asteroids, and bullets based on their speeds. Instead of bouncing off the walls, we will make space wrap around. If any object flies off one side of the screen, it will reappear on the opposite side.

while True:
    wn.update()
    time.sleep(0.01)
    player.setx(player.xcor() + player.dx)
    player.sety(player.ycor() + player.dy)
    if player.xcor() > 300: player.setx(-300)
    if player.xcor() < -300: player.setx(300)
    if player.ycor() > 300: player.sety(-300)
    if player.ycor() < -300: player.sety(300)
    for asteroid in asteroids:
        asteroid.setx(asteroid.xcor() + asteroid.dx)
        asteroid.sety(asteroid.ycor() + asteroid.dy)
        if asteroid.xcor() > 300: asteroid.setx(-300)
        if asteroid.xcor() < -300: asteroid.setx(300)
        if asteroid.ycor() > 300: asteroid.sety(-300)
        if asteroid.ycor() < -300: asteroid.sety(300)
    for bullet in bullets[:]:
        bullet.setx(bullet.xcor() + bullet.dx)
        bullet.sety(bullet.ycor() + bullet.dy)
        if bullet.xcor() > 300 or bullet.xcor() < -300 or bullet.ycor() > 300 or bullet.ycor() < -300:
            bullets.remove(bullet)
            bullet.hideturtle()

# Next: 8. Collision Detection


8
Collision Detection

Finally, we need to program what happens when objects hit each other. The computer doesn't automatically know when two shapes touch; we have to tell it to check the distance between them. Important: This code belongs inside the
while True:
loop. Make sure you indent it carefully in Thonny so it aligns with the code from Step 7!

    for asteroid in asteroids[:]:
        if player.distance(asteroid) < 20:
            player.hideturtle()
            asteroid.hideturtle()
            pen.goto(0, 0)
            pen.write("GAME OVER", align="center", font=("Courier", 36, "normal"))
            break
    for bullet in bullets[:]:
        for asteroid in asteroids[:]:
            if bullet.distance(asteroid) < 20:
                bullets.remove(bullet)
                asteroids.remove(asteroid)
                bullet.hideturtle()
                asteroid.hideturtle()
                score += 10
                pen.clear()
                pen.write(f"Score: {score}", align="center", font=("Courier", 24, "normal"))
                break

# ...and we're done!


USE - MODIFY - CREATE

image
Once you have read the guidance on each part of the game (you did read the guidance, didn't you?) and carefully checked your indentation inside the main loop, click "Run" (green play button) in Thonny to test your game! Read Thonny's error messages closely to debug your code if things don't work the first time.

Fly around the screen, dodge the asteroids, and shoot them to score points. See how high you can get your score before you crash!

USE - MODIFY - CREATE

image
Now that you have a working game, it is time to make it your own. Try finding the specific lines of code in your script in the challenges below and changing the values to see what happens.

1
A New Coat of Paint

Change the look of your game by altering the colours to match your own style.

Find the line that sets the background colour:
wn.bgcolor("black")
.
Try changing "black" to "navy" or "#000020".
Locate the player and asteroid colour settings:
player.color("blue")
and
asteroid.color("grey")
.
Pick your favourite colours and swap them in!

2
Adjust Ship Handling

Is the ship too fast or too slow to control? You can change how it handles.

Find the functions
turn_left()
and
turn_right()
and change the turning angle from
20
to something smaller like
10
for finer control, or larger like
30
for a faster turn.
In the
increase_thrust()
function, change the multiplier
0.2
to a higher value like
0.4
to make the ship accelerate faster.

3
Asteroid Field Density

You can tweak how dangerous space is by changing the number and speed of the asteroids.

At the start of the asteroid creation code, find
for _ in range(10):
. Change
10
to
5
for an easier game, or
20
for a much more crowded field.
In the same section, find where
dx
and
dy
are set. Changing
random.uniform(-1, 1)
to
random.uniform(-2, 2)
will make the asteroids move much faster.

4
Weapon Power

Change how fast your laser bullets travel.

Inside the
fire_bullet()
function, look for where the bullet's
dx
and
dy
are set.
Change the speed multiplier from
5
to
10
to make your shots twice as fast.

5
Customise the Scoreboard

Make the game interface uniquely yours.

Locate the text written to the screen by the
pen
turtle.
Change the score message from
f"Score: {score}"
to something like
f"Points: {score}"
.
Alter the font, size, and style to your liking.

USE - MODIFY - CREATE

image
Finished early? Your Asteroids game works, but it is missing a few classic arcade features. Pick one or more of the challenges below to upgrade your project. You will need to think carefully about where in your existing code these new instructions belong.

1
Multiple Lives

Create a lives variable set to 3 and display it on the screen with your score.
Modify the player-asteroid collision code so that it subtracts a life instead of ending the game. Reset the player's position and speed to the centre of the screen.
When lives reach 0, clear the screen and display the "Game Over" message.

2
Splitting Asteroids

This is a classic Asteroids feature! Modify the bullet-asteroid collision code.
When a normal-sized asteroid is hit, instead of just disappearing, have it create two new, smaller asteroids.
You will need to give these new asteroids slightly different
dx
and
dy
values so they fly apart. You could use
asteroid.shapesize()
to make them look smaller.

3
Hyperspace Jump

Add a new function called
hyperspace_jump()
.
This function should instantly move the player to a random
(x, y)
coordinate on the screen.
Link this function to a key, for example, the "Down" arrow, so the player can use it to escape a dangerous situation. Be careful, you might jump right on top of another asteroid!

4
Inertial Dampening

Real spaceships don't stop instantly. Add a small amount of "drag" or "friction" to the ship's movement.
Inside the main game loop, slightly reduce
player.dx
and
player.dy
on every frame by multiplying them by a number just less than 1 (e.g.,
player.dx *= 0.99
). This will make the ship gradually slow down when you are not using the thrusters.

5
Add Sound Effects

Depending on your operating system, research how to import the
winsound
module for Windows or the
os
module for macOS/Linux.
Trigger a "pew" sound when a bullet is fired and an "explosion" sound when an asteroid is destroyed.

image
Last modified: July 1st, 2026
The Computing Café works best in landscape mode.
Rotate your device.
Dismiss Warning