python asteroids
Build a classic game of asteroids using Python Turtle
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.
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
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
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
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.
Last modified: July 1st, 2026
