Tiny Asteroids for Microbit

Asteroids is a game I used to love to play on the old Atari 2600 console.

asteroids

Even though the graphics are pretty basic by modern standards, the microbit can't hope to come anywhere near it because of its minimal graphical capability.

Or can it?

Choices

Cutting the game down to its minimum to work on a 5x5 screen meant that we could only have one asteroid on the screen at a time and couldn't really support driving around the screen the way that the original ship did.

Brightness

Asteroids are represented as single dots with random brightness and enter at a random position at the top of the screen, travelling down the screen until the reach the bottom. Each time an asteroid reaches the bottom of the screen, a new one is generated at the top.

The ship is represented as a fully bright dot in the centre at the bottom of the screen. The buttons A and B can be used to move the ship left and right to avoid the moving asteroids.

Animation

The game ends when an asteroid crashes into the ship. Rather than just displaying something like as sad face as game over, I put a little bit of time into creating an explosion or firework animation with dots radiating out from the crash and gradually fading from normal brightness down to nothing.

Code

Here's the finished code:


# Tiny Asteroids with exploding ship for Microbit

from microbit import *
import random

# board dimensions
pixel_width, pixel_height = 4, 4
Frame_Rate_In_Milliseconds = 500

# general game functions

def display_count_down(fromValue):
    for i in range(fromValue, 0, -1):
        display.show(str(i))
        sleep(1000)

def display_game_over(ship, score):
    # blow up ship
    # take x of ship and blow up outwards
    blow_up_ship(ship)
    sleep(500)
    display.show(Image.SAD)
    sleep(500)
    display.scroll("Score: " + str(score))

# ship functions
# bottom part of the screen, in the middle
def create_ship():
    # x, y, brightness
    return [2, 4, 9]

def hide_ship(ship):
    display.set_pixel(ship[0], ship[1], 0)

def draw_ship(ship):
    display.set_pixel(ship[0], ship[1], ship[2])

def move_ship_left(ship):
    ship[0] = max(ship[0] - 1, 0)
    return ship

def move_ship_right(ship):
    ship[0] = min(ship[0] + 1, pixel_width)
    return ship

def blow_up_ship(ship):

    hide_ship(ship)

    draw_explosion(ship, ship[2], 1)
    sleep(200)
    display.clear()

    for brightness in range(ship[2], 0, -1):
        draw_explosion(ship, brightness, 2)
        sleep(200)
        display.clear()

    # look at x position
def draw_explosion(centre, brightness, radius):

    x = centre[0]
    y = centre[1]
    left_of_centre = x - radius
    right_of_centre = x + radius
    above_centre = y - radius

    if left_of_centre >= 0:
        display.set_pixel(left_of_centre, y, brightness)
        display.set_pixel(left_of_centre, above_centre, brightness)

    display.set_pixel(x, above_centre, brightness)

    if right_of_centre <= pixel_width:
        display.set_pixel(right_of_centre, y, brightness)
        display.set_pixel(right_of_centre, above_centre, brightness)

# asteroid functions

def hide_asteroid(asteroid):
    display.set_pixel(asteroid[0], asteroid[1], 0)

def draw_asteroid(asteroid):
    display.set_pixel(asteroid[0], asteroid[1], asteroid[2])

def create_asteroid():
    # x, y, brightness, maybe speed.., size
    minimum_brightness = 3
    maximum_brightness = 8
    return [ random.randint(0, pixel_width), 0, random.randint(minimum_brightness, maximum_brightness) ]

def asteroid_collides_with_ship(asteroid, ship):
    return (asteroid[0] == ship[0]) and (asteroid[1] == ship[1])

def move_asteroid(asteroid):
    asteroid[1] += 1
    return asteroid


score = 0

ship = create_ship()
asteroid = create_asteroid()

# game start
display_count_down(5)
display.clear()

# Game loop
while True:

    draw_ship(ship)
    draw_asteroid(asteroid)

    # increase speed once we are above a certain score...
    sleep(Frame_Rate_In_Milliseconds)

    if asteroid_collides_with_ship(asteroid, ship):
        display_game_over(ship, score)
        break

    hide_ship(ship)
    hide_asteroid(asteroid)

    if asteroid[1] == pixel_height:
        score += 1
        asteroid = create_asteroid()
    else:
        # check for button pushes...
        if button_a.was_pressed():
            #display.scroll('A')
            ship = move_ship_left(ship)
            #display.scroll(str(ship[0]) + ' ' + str(ship[1]))
        elif button_b.was_pressed():
            ship = move_ship_right(ship)

        asteroid = move_asteroid(asteroid)
        

This might be my most ambitious game for the microbit even though the tiny screen does mean that representing the ship and the asteroids are not a satisfying as I would have wanted.

I'm most proud of the end of game explosion showing the asteroid crashing into the ship. It wasn't hard to do and offers a nice little flourish to the minimalist experience :)