I’ve managed to get a simple game working on my micro:bit OLED display, and I ditched the breadboard at the same time, meaning that it should be possible to build this into a small case. I may even add some external buttons and perhaps some sound?
Here’s what I used:
- A micro:bit
- A Pimoroni pin:bit edge connector (the Adafruit DragonTail would work equally well, with the Kitronik one you have to solder extra pins to get to the i2c interface pins).
- 4 female to female jumper wires
- A cheap 0.96″ SSD1306 OLED display
- The online Python editor for micro:bit
- Some of these Python libraries: https://github.com/fizban99/microbit_ssd1306 – ssd1306, _stamp, _img and _text
I added the extra Python modules using the new micro:bit Python editor’s feature to add extra files to your projects. It supports WebUSB, so using a recent version of Chrome you can flash Python projects straight onto your micro:bit without having to drag and drop HEX files.
Connecting the OLED is easy, especially if you have the well-labelled pin:bit – connect micro:bit 3v to VCC on the display, GND to GND, micro:bit pin 19 SCL (serial clock) to the display’s SCL pin and micro:bit pin 20 (SDA / serial data) to the SDA pin on the display.
The program works by creating ‘stamps’ – like crude sprites – for 3 hazards (a duck, a ghost and a tortoise), all using graphics from the micro:bit’s own built-in 5×5 icons. This is a neat touch that avoids having to create your own bitmap graphics.
You move left and right using A and B buttons, and press A+B together to move forward – you can’t move backwards! When you reach the top you level up, complete 10 levels to win.
There was no function I could find in the Python modules to invert the screen, which is possible if you know what control codes to send, so I added the flash() function which will flash the screen any number of times by making the screen negative then positive quickly in succession. I use this effect when you level up, win or lose.
The levels don’t get harder – it’s running as fast as it can, so I can’t speed it up. To make it more challenging I might add more hazards or slow the player down in some way. Adding sound would also be a logical next step, along with building into a small case, perhaps with some external buttons.
My main Python game program is here, and you can download the whole project HEX file here.
from ssd1306 import initialize, clear_oled, command from ssd1306_stamp import draw_stamp from ssd1306_img import create_stamp from ssd1306_text import add_text from microbit import sleep, display as LED, Image, button_a as A, button_b as B def flash(times): for i in range(times): command([0xa7]) sleep(300) command([0xa6]) sleep(300) def move_stamp(x1, y1, x2, y2, stmp): draw_stamp(x1, y1, stmp, 0, 0) draw_stamp(x2, y2, stmp, 1, 1) alive = True level = 0 ghostx, ghosty = 3, 10 ghostDirection = 1 tortoiseX, tortoiseY = 40, 20 tortoiseDirection = -1 duckX, duckY = 20, 5 duckDirection = 1 playerX, playerY = 32, 27 LED.show(level) initialize() clear_oled() ghost = create_stamp(Image.GHOST) tortoise = create_stamp(Image.TORTOISE) duck = create_stamp(Image.DUCK) player = create_stamp(Image.TRIANGLE) draw_stamp(ghostx, ghosty, ghost, 1) draw_stamp(tortoiseX, tortoiseY, tortoise, 1) draw_stamp(duckX, duckY, duck, 1) draw_stamp(playerX, playerY, player, 1) while alive: oldGhostX = ghostx ghostx += ghostDirection if ghostx > 58: ghostDirection = -1 if ghostx < 3: ghostDirection = 1 move_stamp(oldGhostX, ghosty, ghostx, ghosty, ghost) oldTortoiseX = tortoiseX tortoiseX += tortoiseDirection if tortoiseX > 58: tortoiseDirection = -1 if tortoiseX < 3: tortoiseDirection = 1 move_stamp(oldTortoiseX, tortoiseY, tortoiseX, tortoiseY, tortoise) oldDuckX = duckX duckX += duckDirection if duckX > 58: duckDirection = -1 if duckX < 3: duckDirection = 1 move_stamp(oldDuckX, duckY, duckX, duckY, duck) oldPlayerX = playerX playerX = playerX - 1 if (A.is_pressed() and playerX > 0) else playerX playerX = playerX + 1 if (B.is_pressed() and playerX < 58) else playerX oldPlayerY = playerY playerY = playerY - 1 if (A.is_pressed() and B.is_pressed() and playerY > 0) else playerY if oldPlayerX != playerX or oldPlayerY != playerY: move_stamp(oldPlayerX, oldPlayerY, playerX, playerY, player) # have we reached the top? if playerY == 1: level = level + 1 LED.show(level) flash(1) draw_stamp(playerX, playerY, player, 0) playerX, playerY = 32, 27 draw_stamp(playerX, playerY, player, 1) # have we won? if level == 10: alive = False # have we hit anything? if ghostx-3 <= playerX <= ghostx+3 and ghosty-3 <= playerY <= ghosty+3 \ or tortoiseX-3 <= playerX <= tortoiseX+3 and tortoiseY-3 <= playerY <= tortoiseY+3 \ or duckX-3 <= playerX <= duckX+3 and duckY-3 <= playerY <= duckY+3: alive = False if level == 10: LED.show(Image.HAPPY) clear_oled() add_text(3, 1, 'You win!') flash(5) else: LED.show(Image.SKULL) clear_oled() add_text(2, 1, 'Game over!') flash(5)
Hi, I followed your tutorial and got the game to work. I tried to make it more complicated by making the ghost move faster.
The result was a trailing ghost :
https://www.youtube.com/watch?v=T3bnkqbmJaM&feature=emb_title#
http://blogs.brighton.ac.uk/ccdigifab/2020/03/15/embedded-programming-mircobit-oled-game/
Is this what you were referring to when you mention “it’s running as fast as it can”?
Thanks – Christy
Hi Christy – that’s awesome! I don’t know why your ghost is, er, ghosting, but I am going to have a play with your code. It would be cool if we could create some more little micro:bit games for OLED displays, they’re relatively inexpensive and very easy to connect if you have a breakout board.
best wishes
Giles
This is fantastic. I’m teaching middle school students how to use the microbit, and I’d love to do this with them, but I can’t figure out how to get the libraries from GitHub to the Micro:Bit Python editor and/or onto the Micro:Bit. I just get an error message flashing when I try to copy your code to the python editor and flash the Micro:Bit. Any advice?
Hi Don – glad you like this and I’m delighted you’re teaching with the micro:bit!
It’s been a while since I played with the OLED display so let me try and remember!
What is the error message you’re getting?
I’m guessing the problem is caused by missing libraries, so here are a few things to try:
First download and flash the whole crossy_ducker2.hex file if you haven’t done so already in order to check the hardware.
Next, you can drag that HEX file into the online Python editor at https://python.microbit.org/ and view it that way. Then click on the load/save icon and you should see listed under ‘project files’ 5 Python files, the main program and 4 library files that contain various drivers for the display:
crossy_ducker2 (main.py)
ssd1306.py
ssd1306_stamp.py
ssd1306_img.py
ssd1306_text.py
Hope that helps! Let me know how you get on.