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)