RustScape
A compact and robust 2D video game for the NUCLEO-F411RE, written in Rust.
Author: Mihnea Girbacica
GitHub Project Link: https://github.com/UPB-PMRust-Students/project-Mihnea8848
Description
RustScape is a 2D platformer game that aims to deliver a classic handheld gaming experience on a minimal embedded system. It's built for the NUCLEO-F411RE development board, pushing the boundaries of what's possible with microcontroller-based game development. Graphics are rendered on a vibrant 1.8" SPI TFT display (ST7735R), reminiscent of retro handhelds, while player control is achieved through an analog joystick and D-Pad Shield combo (KY-023) for movement, being a perfect choice for achieving that "retro feel". To complete the immersion, two passive buzzers provide a very makeshift soundtrack for the game and chiptune-style audio feedback. In the spirit of the DIY ingenuity, the project tries to embrace a cost-effective approach, even aiming to house the final product within the NUCLEO-F411RE's original cardboard shipping box. In the final version of this project, the players should be immersed in the game's story, overlooking the... less than desirable appearance and cheap parts.
Motivation
As the owner of a Game Development Company, I've been fascinated by video games since childhood. The curiosity to understand their creation has always driven me. While my current work involves developing cross-platform titles for PC, Android, Linux, and VR (see https://www.roblox.com/games/3192370355/MEH-Studios-Research-Facility-Test-Server for more details), I've always held a particular fondness for retro games and the challenge of emulation. This project, with its requirement to use microprocessors, presented the perfect opportunity to combine my passion for game development with the exploration of embedded systems, allowing me to create a physical, playable tribute to classic handheld gaming. With that being said, due to the limitations (Flash Storage Space), it forces me to fix my habit of writing spaghetti code, leaving optimizations at last, or even skipping them altogether.
Architecture
As stated before, this project uses a Nucleo-F411RE Development Board at its core. To the microprocessor, the following parts were connected:
- An 1.8" SPI TFT LCD Display, used to display the game,
- Two Passive Buzzers that are used to play the soundtrack of the game,
- An Arduino SHIELD (Joystick + DPad Combo) used to interact with the game, mainly to move the player.
The previoulsy stated configuration can be seen in the diagram below, as well as the KiCAD Schematic, that can be found later on in this documentation.
Log
Week 5 - 11 May
The main goal of the first week was to make all of the peripherals work.
Code Changelog:
- Created the Cargo.toml, with all the required dependencies
- Created module display_module.rs, that integrates the ST7735s display to the microcontroller
- Created module sound_module.rs, that integrates the 2 Passive Buzzers (one for Bass and one for Melody) to the microcontroller
- Created module controller_module.rs, that integrates all of the SHIELD buttons to the microcontroller.
Hardware Changelog:
- Decided to use the cardboard shipping box of the NUCLEO-F411RE as the chassis of the project
- Test fitted the following parts to the box: ST7735s, 2x Passive Buzzer, Fundruino SHIELD
- Glued inside of the box a small 3V3 and GND bus, taken from a small breadboard
- Tested the placement of the buzzers so that the soundtrack can be heard easily
Photos:
Week 12 - 18 May
This week's goal was to start making the game's logic, mainly the player movement and loading up levels. I experimented different ways to load images onto the screen, but I ended up using .raw image files for their versatility and, most importantly, their relatively low storage footprint.
Code Changelog:
- Added game_module.rs, that includes very crude game logic (player movement, background loading)
- Improved the game_module.rs to move the background when the player moves to undisplayed areas.
- Optimized the code so that it works better (!)
- Created and added all of the required assets (The player in all of its states, the background for level1)
- Made the player stripe change based on what input is provided on the D-Pad
- Made the player stripe change it's location (move) based on the input
- Considering adding another microcontroller to the project (!)
Hardware Changelog: No hardware changes were made this week.
In this stage of development, I discovered that the NUCLEO-F411RE is severely limited in terms of RAM and FLASH storage. I am considering adding another microcontroller, most likely the ESP32 WROOM32, to drive the display. This will substantially increase the performance of the game.
Photos:
Week 19 - 25 May
As stated in the previous week's progress log, I discovered the NUCLEO's severe limitations in terms of hardware. While I considered implementing the ESP32 WROOM32 as a graphics controller, I decided against it, sticking with only the NUCLEO-F411RE microcontroller. The reasoning behind this is that "Anyone can put a better engine in their car, but that doesn't make themselves a better driver."
This week was by far the hardest week. Since I decided not to include another microcontroller, I tried optimizing the code as much as possible, so that the game will fit on the mere 512KB of FLASH storage. Some optimizations include:
- Reducing the images size by changing the file type from .png to .raw,
- Using a Python script to compress the .raw files as much as possible, while also retaining the image quality,
- Optimized the way the code handles the images and how they are loaded into RAM (only 128KB).
Code Changelog:
- Changed the camera movement from dynamic to chunk-based (part of the code optimizations),
- Reduced the file size of level1 to 2-bytes-per-pixel (part of the code optimizations),
- Changed the way the player is loaded, as well as how the background behind the player is loaded (part of the code optimizations),
- Added a Hitbox map for level1, so that the level doesn't feel like a plain image,
- Reduced the Hitbox map to 1-byte-per-pixel, to reduce the file size (part of the code optimizations),
- Re-added the boot-up sequence, the main menu and the soundtrack functionality.
Hardware Changelog: As stated before, I decided against adding another microprocessor, therefore, no hardware changes were made this week.
Photos:
Hardware
RustScape is built using the NUCLEO-F411RE development board, which acts as the game's central processing unit. Visuals are rendered on a 1.8" SPI TFT display. Player input is managed via a shield integrating an analog joystick and buttons, enabling movement and actions. Audio feedback is delivered through two passive buzzers, generating sound effects and simple music. Jumper wires ensure flexible electrical connections. Power and code uploads are facilitated by a Mini-USB to USB-A cable. Finally, an 8-LED module is used to represent the player's health status. All components, including the NUCLEO-F411RE board, are housed within the original NUCLEO-F411RE box, serving as a budget-friendly enclosure for the handheld console.
Schematics
This is the finished KiCAD Schematic for RustScape:
Bill of Materials
Device | Usage | Price |
---|---|---|
STM32 NUCLEO-F411RE | Microcontroller that drives the peripherals, as well as game logic | 70 RON |
1.8" SPI TFT Display | 128x160 Color screen that displays the game | 29 RON |
KY-023 Analog Joystick | Joystick + buttons for player movement | 20 RON |
2 x Passive Buzzer | Audio feedback and soundtrack for the game | 2 RON |
Mini-USB to USB-A Cable | USB Cable for power and code flashing | 4.5 RON |
Jumper Wires | 2 x Male-male & 1 x Female-female Cables | 17 RON |
8 Red LED Module | 8 LEDs to display the player health | 11.5 RON |
Software
Library | Description | Usage |
---|---|---|
embassy-stm32 | HAL for STM32 | Abstracts the NUCLEO-F411RE's hardware (SPI, GPIO, Timers) for easier control. |
embassy-executor | Asynchronous runtime | Enables non-blocking operations for smooth gameplay. |
embassy-time | Asynchronous timing | Provides delays and timing for game logic and display updates. |
display-interface-spi | SPI display interface | Handles low-level communication with the ST7735R. |
mipidsi | ST7735 driver | Offers display initialization and control. |
embedded-graphics | 2D graphics library | Draws shapes, text, and other visuals on the screen. |
defmt | Logging framework | Provides efficient debugging output. |
panic-probe | Panic handler | Improves error handling during crashes. |
cortex-m-rt | Cortex-M runtime | Sets up the microcontroller environment. |
Links
I plan on using this project after PMFair as part of an educational programme for my company, MEH Studios Incorporated. More details can be found below:
- MSINC Website (Note: This link might change in the future, search MEH Studios Incorporated on Google for permanent links.)
YouTube Backup
There exists a rather high possibility that the project won't work at PMFair, due to loose cables which are unaccessible, or due to the microcontroller malfunctioning. Therefore, I uploaded an unlisted YouTube video on my channel, showcasing the whole project in a late stage of development (roughly ~85% or ~90% done). This video is to be used as a backup: