A Rust-based monochrome pixel game engine that can be compiled to both web assembly (javascript canvas used for display) and also to the RP2040 microcontroller (which uses the monochrome SSD1306 display over I2C). I'm mainly making this so that I can bring hardware to Daydream (the final game apparently has to be uploadable to itch.io, hence the WASM support).
555 timer
Check their project out: DOOMkey
Once you ship this you can't edit the description of the project, but you'll be able to add more devlogs and re-ship it as you add new features!
Got the demo working! Just need to compile it for the pico (I need to add the inputs to the pico HAL for that, maybe another hour or so of work, then I'm ready to deploy the demo somewhere and ship!)
Keyboard inputs in wasm work now!! That was quite annoying to do because it turns out that there's no API to get the current state of a key, you have to work it out yourself using event listeners. Time to make the demo! Then I'll do the first ship, and then add some quality-of-life features like builtin sprite rendering, but the core engine is basically done.
Display output in wasm is working! That went smoother than expected and I also made it a nice colour scheme. The canvas is pixel-perfect responsive (and all that logic is in rust because I'm not touching javascript with a metre stick if I can avoid it).
Lesson of the day: mixing async + non-async code = pure pain and suffering. I somehow made it work but it's pain. Also I still don't understand what the hell static lifetimes are but they seem to make the compiler happy. Anyway, delays in wasm work now and the code doesn't crash the main thread anymore. yay.
Next up is figuring out how to render to a canvas.
Refactored the project to be able to use wasm-pack and added a little webpack npm runner to run the devserver, printing stuff to the console works so we should be good. Just need to implement the HAL for wasm now, then I'll get inputs working, make a simple demo (maybe a dot moving around the screen controlled by wasd/arrows) and then ship the first version. I hope I can get that done by tonight.
Did some more work on individual pixel addressing and framebuffer stuff, here's a nice little pixel scanning across the screen row by row. Also ticks work now, I set the tick rate to ~60 ticks/sec. I need to work on the wasm side of things now, just need to create a HAL for web assembly.
Writing to the display now works! Here are some nice horizontal lines :D
Other stuff I've been up to:
- Added a 64KiB heap using embedded-alloc for dynamic memory allocation (don't need it now but will need it in the future)
- Implemented a generic framebuffer
- Found a bug/oversight in rp2040_hal (no good way to make two back-to-back i2c transactions without a stop/restart in between. logic analyser came in clutch for that one)
I added the function to initialise the display (the display's buffer is not cleared at startup so it makes this nice random pattern from the noise in the buffer, this isn't an issue as it goes away when you display the first frame). Next what I need to add is some function to put the pico's framebuffer data onto the display's framebuffer
I think I'm starting to figure out how Rust works but everything is taking 4x as long as it should because I'm still a clueless beginner to embedded Rust. I decided to say screw it, let's refactor the code because the old structure was stupid and hard to maintain, especially with 2 compile targets for pico and wasm. Speaking of wasm, I haven't done much in terms of that but I have started work on the ssd1306 driver code to drive the screen (I'm not using external crates for this because who likes to use libraries when you can do it yourself? It's pretty simple anyway because I'm just porting over the display driver code from my pico flappy bird project, which also used an ssd1306 but was written in C). Pictures are mandatory on devlogs, so here's a picture of the current setup I guess.
Clock and peripherals initialisations for the Pico are done, it took a while because this is one of my first projects using Rust and I was busy playing karate with the compiler
Did some boilerplate stuff, mostly just initialising the project structure and getting compilation to both RP2040 and WASM working.