Table of Contents
At Zaitronics, we've recently built an upgraded version of a Raspberry Pi Pico 2, called Nexus RP2350 LiPo, with the intension of being a drop in replacement for any existing Pico projects. To demonstrate the board's capabilities, I've designed a simple Space Dodger game which requires very few parts most makers should have. For this version, we used a 1.3 inch OLED from Waveshare, but any similar small display should work with slight adjustments in the code.
Parts List:
Wiring (if you are not using the Nexus + OLED stack)
| OLED Pin | RP2350 / Pico Pin |
|---|---|
| VCC | 3.3 V |
| GND | GND |
| SCK | GP10 |
| MOSI | GP11 |
| DC | GP8 |
| RST | GP12 |
| CS | GP9 |
| Button | RP2350 / Pico Pin |
|---|---|
| Button A (UP | GP15 + GND (internal pull-up used) |
| Button B DOWN | GP17 + GND (internal pull-up used) |
How to Play
- Button A (GP15) → move ship UP
- Button B (GP17) → move ship DOWN
- Avoid the white squares coming from the right
- Your score is survival time + 10 points per dodged ball
- The game gets faster the longer you survive
Tweaking Difficulty
| Variable | Effect | Suggested range |
|---|---|---|
| ball_speed = 1.8 | Starting speed | 1.2 – 2.5 |
| speed_increment | How quickly it accelerates | 0.0005 – 0.002 |
| Spawn chance line | How often new balls appear | 0.02 – 0.06 |
| Ball size in loop | 6×6 is good visibility | 4–8 |
Complete Ready-to-Flash Code (MicroPython)
Copy the entire code below into Thonny (or any MicroPython IDE) and save as main.py on your board.
from machine import Pin, SPI import framebuf, time, random # Display pins DC = 8 RST = 12 MOSI = 11 SCK = 10 CS = 9 # Button pins keyA = Pin(15, Pin.IN, Pin.PULL_UP) keyB = Pin(17, Pin.IN, Pin.PULL_UP) # OLED driver class (same as yours) class OLED_1inch3(framebuf.FrameBuffer): def __init__(self): self.width = 128 self.height = 64 self.rotate = 0 self.cs = Pin(CS, Pin.OUT) self.rst = Pin(RST, Pin.OUT) self.cs(1) self.spi = SPI(1, 20000000, polarity=0, phase=0, sck=Pin(SCK), mosi=Pin(MOSI), miso=None) self.dc = Pin(DC, Pin.OUT) self.dc(1) self.buffer = bytearray(self.height * self.width // 8) super().__init__(self.buffer, self.width, self.height, framebuf.MONO_HMSB) self.init_display() self.white = 0xffff self.balck = 0x0000 def write_cmd(self, cmd): self.cs(1) self.dc(0) self.cs(0) self.spi.write(bytearray([cmd])) self.cs(1) def write_data(self, buf): self.cs(1) self.dc(1) self.cs(0) self.spi.write(bytearray([buf])) self.cs(1) def init_display(self): self.rst(1) time.sleep(0.001) self.rst(0) time.sleep(0.01) self.rst(1) for cmd in ( 0xAE, 0x00, 0x10, 0xB0, 0xDC, 0x00, 0x81, 0x6F, 0x21, 0xA1 if self.rotate == 180 else 0xA0, 0xC0, 0xA4, 0xA6, 0xA8, 0x3F, 0xD3, 0x60, 0xD5, 0x41, 0xD9, 0x22, 0xDB, 0x35, 0xAD, 0x8A, 0xAF ): self.write_cmd(cmd) def show(self): self.write_cmd(0xB0) for page in range(0, 64): self.column = page if self.rotate == 180 else 63 - page self.write_cmd(0x00 + (self.column & 0x0F)) self.write_cmd(0x10 + (self.column >> 4)) for num in range(0, 16): self.write_data(self.buffer[page * 16 + num]) # Initialize display OLED = OLED_1inch3() # Ball list: each ball is [x, y] balls = [] # Spaceship position ship_x = 0 ship_y = 28 ship_w = 6 ship_h = 6 # Draw spaceship def draw_ship(x, y, scale=2): """ Draw the spaceship pattern at (x, y) scale: how many screen pixels per pattern pixel """ pattern = [ "00000000000", "000xxx00000", "0000xxxx000", "xxxxxxxxx00", "00xxx00xxx0", "0xxxx000xxx", "00xxx00xxx0", "xxxxxxxxx00", "0000xxxx000", "000xxx00000", "00000000000", ] for row_idx, row in enumerate(pattern): for col_idx, pixel in enumerate(row): if pixel == "x": OLED.fill_rect(x + col_idx*scale, y + row_idx*scale, scale, scale, OLED.white) import time # Game variables score = 0 ball_speed = 2 # initial speed of balls speed_increment = 0.05 # increase speed over time start_time = time.ticks_ms() # start timer # Main loop while True: OLED.fill(0) # clear screen # Update score based on elapsed time elapsed_ms = time.ticks_diff(time.ticks_ms(), start_time) score = elapsed_ms // 100 # roughly increments every 0.1 second # Display score OLED.text("Score: {}".format(score), 0, 0) # Move spaceship up/down if keyA.value() == 0: # up ship_y = max(0, ship_y - 2) if keyB.value() == 0: # down ship_y = min(OLED.height - ship_h*2, ship_y + 2) # scale=2 # Randomly spawn a new ball on the right if random.random() < 0.05: # reduce spawn rate for balance y = random.randint(0, OLED.height - 4) balls.append([127, y]) # Draw and update balls new_balls = [] for ball in balls: x, y = ball OLED.fill_rect(x, y, 4, 4, OLED.white) # 4x4 ball x -= int(ball_speed) # move left if x > 0: new_balls.append([x, y]) balls = new_balls # Gradually increase speed ball_speed += speed_increment / 50 # slow acceleration # Draw spaceship draw_ship(ship_x, ship_y) OLED.show() time.sleep(0.05)
Additional Resources
- Full Driver & Examples: Check the Waveshare wiki for the original MicroPython library: https://www.waveshare.com/wiki/Pico-OLED-1.3 (includes C/C++ too).
- Customization Ideas: Modify the ship pattern, add a buzzer on GP16 for collision sounds, or implement high-score saving to onboard flash.