Stage 4: Spawn the Alien Fleet
Keep building in the workspace on the right.
This stage is part of the same Python Arcade project you started in Setup. Type each new code block into the Trinket rail and keep building on the last stage.
a grid of enemy turtles lined up like an arcade fleet
how nested loops build rows and columns from one helper
a multi-row alien fleet waiting at the top of the screen
The big idea
Last stage you built the most reusable pattern in the whole course: a list of game objects + a game loop that walks the list. Today we use it again. Aliens are temporary game objects, just like lasers — they appear, move, and get cleaned up.
What changes is the layout. Lasers spawn one at a time from the cannon. Aliens need to start as a formation: multiple rows and columns lined up near the top of the screen, like a classic space-invader fleet.
Stage 3 — Lasers: Stage 4 — Aliens:
player presses space -> make a grid once
│ │
▼ ▼
fire_laser() spawn_alien_fleet()
│ │
▼ ▼
lasers.append(...) aliens.append(...) for each alien
The list, the append, and the cleanup are still reused. A fleet is not a new data structure yet. It is regular alien Turtles added to the same aliens list, one alien at a time.
The new tool today is a nested loop. One loop walks through Y positions for rows. Inside it, a second loop walks through X positions for columns. That pair of loops is how one helper turns into a full arcade formation.
Your cannon should move, and pressing space should fire lasers.
Build it
Step 1 — Decide the alien rules
Just like the laser cap, we make the alien numbers easy to tune. ALIEN_COLUMNS are the X positions across the screen. ALIEN_ROWS are the Y positions stacked near the top.
Add these near your other constants:
ALIEN_COLUMNS = [-240, -120, 0, 120, 240]
ALIEN_ROWS = [TOP - 40, TOP - 90, TOP - 140]
aliens = []
aliens = [] is the empty list, exactly like lasers = [] from Stage 3. The shape of the pattern is already familiar.
ALIEN_COLUMNS is the column map. Each number is an X position. ALIEN_ROWS is the row map. Each number is a Y position. Together, they make a grid.
Step 2 — Write the alien helper
This helper builds one alien — a new Turtle, colored and shaped, dropped at one column in the row — and puts it in the list. From that moment on, the game owns the alien through the list.
Build this helper above the game loop:
Write the alien like a laser
Before looking at the full helper, write the first four lines of make_alien(x, y) from memory by reusing the pattern of fire_laser(), not the exact values.
Need a hint?
Build the Turtle, lift the pen, choose color and shape, choose a position, then append it to `aliens`.
Stuck? Compare carefully
main.py
Write the first four lines from the laser pattern first, then reveal to check the whole function.
def make_alien(x, y):
alien = turtle.Turtle()
alien.penup()
alien.color("lime")
alien.shape("circle")
alien.setposition(x, y)
aliens.append(alien)
The helper takes x and y as parameters. That means the row function can decide where aliens go, and this helper only handles how one alien is built.
Step 3 — Spawn the full fleet
Now write the function that makes the formation. The outside loop picks a row. The inside loop fills that row with aliens across every column.
Stuck? Compare carefully
main.py
Write the loop yourself first, then reveal to check.
def spawn_alien_fleet():
for y in ALIEN_ROWS:
for x in ALIEN_COLUMNS:
make_alien(x, y)
This is the moment the aliens line up. Three Y positions times five X positions makes fifteen aliens, all still stored in one flat aliens list.
Step 4 — Create the fleet before the loop
Now wire the fleet into the program. We want a starting formation, so call the function once before the game loop begins.
Put this after your key bindings and draw_cannon() call, just before while True::
Nested loop size
If `ALIEN_COLUMNS` has 5 numbers and `ALIEN_ROWS` has 3 numbers, how many aliens does `spawn_alien_fleet()` make?
Check your thinking
15 aliens. The nested loop makes one alien for every row-column pair.
spawn_alien_fleet()
Run the game. A multi-row fleet should appear near the top. It will not move yet — that happens in Stage 5 — but it should look like a real arcade formation, not one overlapping row.
Optional — Skin the circle aliens with sprite files
The circle aliens are the reliable baseline. After they spawn correctly, you can make those same alien Turtles use the colored pixel sprites from the hero image.
If you uploaded the alien GIFs in Setup, add this block near your alien constants:
Upload these GIF files into Trinket with exact filenames. The fallback keeps circle aliens if any file is missing.
main.py
Where it goes: Put this near the alien constants, immediately after `aliens = []`.
Skip this if you are keeping circle aliens.
ALIEN_SPRITES = [
"alien-purple.gif",
"alien-blue.gif",
"alien-green.gif",
"alien-yellow.gif",
"alien-red.gif",
]
USE_ALIEN_SPRITES = True
try:
for sprite in ALIEN_SPRITES:
screen.addshape(sprite)
except:
USE_ALIEN_SPRITES = False
Then replace the appearance lines inside make_alien(x, y) with this version. The alien is still a Turtle in the aliens list; only its visual skin changes:
main.py
Where it goes: Inside `make_alien(x, y)`, replace only the existing `alien.color(...)` and `alien.shape(...)` lines.
Keep the rest of `make_alien(x, y)` in the same order.
if USE_ALIEN_SPRITES:
alien.setheading(270)
alien.shape(ALIEN_SPRITES[len(aliens) % len(ALIEN_SPRITES)])
else:
alien.color("lime")
alien.shape("circle")
Run it. If the uploads worked, aliens appear in the same purple, blue, green, yellow, and red pixel style as the hero image. The setheading(270) line points sprite aliens downward, matching the direction they move in Stage 5. If they appear as lime circles, keep going — the fallback means the game is still playable.
File order checkpoint
By the end of Stage 4, your main.py should be ordered like this:
- Imports at the top:
turtleandtime - Screen setup and constants, including
ALIEN_COLUMNS,ALIEN_ROWS, andaliens = [] - Optional alien sprite setup, if you are using GIF skins
- Helper functions, including
make_alien(x, y)andspawn_alien_fleet() - Key bindings and the existing
draw_cannon()call spawn_alien_fleet()once before the game loop- The game loop, with the Stage 3 laser loop still inside it
Understand it
The whole stage is a lesson in pattern reuse. Look at your code side-by-side: aliens is to lasers what make_alien is to fire_laser. The layout changed, the appearance changed, the position rules changed — but the shape of the code is identical. Recognizing this is a real coding superpower. Next time you need an extra system in a game, ask: "is this a list of things that appear and disappear?" If yes, you already know the bones.
Rows are built from individual aliens on purpose. We could store each row as its own list, but that would make Stage 6's collision loop harder for no benefit. A flat aliens list means every later system can ask the same simple question: "for each alien, what should happen?"
The important detail is that spawn_alien_fleet() runs once, outside the loop. If it ran inside while True:, the program would create a new fleet every frame and flood the screen. If it only made one Y position, the player would see one row. The two lists are what make the formation: ALIEN_COLUMNS controls width, and ALIEN_ROWS controls height.
Try this
Try this
Three short experiments. Predict before you run, then test your guess.
Add one more number to ALIEN_ROWS, like TOP - 190. Before you run, predict how many aliens the fleet will have. Now run it. Did the formation grow the way you expected?
Temporarily move spawn_alien_fleet() inside the game loop. Run for just a second, then stop it. What happened? Put it back before the loop. Why does one line's position change the whole game?
Stage 5 makes the aliens move. Look at your Stage 3 laser game-loop code — specifically the for laser in lasers[:]: block. What needs to change for aliens? What stays exactly the same?
Test your stage
Stuck? Compare carefully
required Stage 4 code
Where it goes: Compare this with the Stage 4 pieces in your file: alien constants before the helper functions, `spawn_alien_fleet()` before the game loop, and the Stage 3 laser loop still inside the game loop.
Use this after you compare the alien pattern to the laser pattern.
ALIEN_COLUMNS = [-240, -120, 0, 120, 240]
ALIEN_ROWS = [TOP - 40, TOP - 90, TOP - 140]
aliens = []
def make_alien(x, y):
alien = turtle.Turtle()
alien.penup()
alien.color("lime")
alien.shape("circle")
alien.setposition(x, y)
aliens.append(alien)
def spawn_alien_fleet():
for y in ALIEN_ROWS:
for x in ALIEN_COLUMNS:
make_alien(x, y)
spawn_alien_fleet()
while True:
# Stage 3 laser loop stays here.
time.sleep(0.02)
screen.update()
- The fleet appears without anyone pressing a key.
- The fleet has multiple rows and five clean columns.
- The cannon and lasers still work.
- The screen does not instantly flood with duplicate fleets.
- Optional sprite check: uploaded alien GIFs render as colored pixel aliens, or the game safely falls back to lime circles.
- Design check. Does the starting formation read like a space-invader fleet, or does it look too sparse?
- From memory. Without looking, write the nested loop that builds the fleet. Compare — did you loop through rows first, then columns?
If it breaks
- Only one row appears. Check that you created
ALIEN_ROWSwith multiple Y positions, and thatspawn_alien_fleet()has two loops:for y in ALIEN_ROWS:and inside itfor x in ALIEN_COLUMNS:. - No aliens appear. Make sure
spawn_alien_fleet()is called once beforewhile True:. Defining the function is not enough; you also have to call it. - The fleet appears off-screen. Check the numbers in
ALIEN_COLUMNS. They should stay betweenLEFT + 40andRIGHT - 40; with the Stage 1 screen,[-240, -120, 0, 120, 240]fits. - The fleet appears too low or too high. Tune the numbers in
ALIEN_ROWS. They should be near the top but still visible. - The fleet spawns but the rest of the game freezes. Check that
spawn_alien_fleet()is not in an infinite loop by mistake. It should use two shortforloops, not its ownwhile True:. - The sprite aliens do not show. Every filename must match exactly. If one upload is missing or renamed,
USE_ALIEN_SPRITESfalls back to the circle alien so the game does not crash.




