Posted April 30, 2021 by thyrotoxicosis
First of all, thanks to all who played my game! RedShift Prototype placed 1st Overall in Bullet Hell Jam 2021, and have received 18 insightful comments, thanks to you. Was it fun for you? I’m deeply grateful to you.
During the jam, some have asked me to do a writeup to document the process, and how the rewind mechanic was implemented. In this post, I hope to expose some of that.
I have always loved bullet hell shooters, and made numerous attempts at making one in the distant past, but those never came to any fruition. The first “bullet hell” I ever made public is Designated Victim back in Ludum Dare 44, where it placed 18th Overall and 10th in Fun. Satisfied with the results of my first LD, I went on to experiment with other genres in a few more game jams that followed.
Until I saw Bullet Hell Jam in my inbox, I didn’t really have a recent plan to build a bullet hell again. As a result, I had to implement any systems from scratch. This did work to my advantage, however, since I was conversely able to architecture the code freely without the bounds of legacy code. This ended up to be somewhat beneficial to the rewind mechanic, as I will later explain.
When the theme, “10 seconds”, came out, I didn’t have any good ideas for it, and throughout the first day, I considered dropping out. It didn’t help that “X seconds” is one of the most common cliches in Ludum Dare slaughter rounds, one of which I have just finished before the jam. Eventually, however, I thought of something. A series of games that shared the initials with what my game was titled with. That’s what inspired me to make the mechanic of time reversal.
Turns out that even with some experience, the basic systems still took quite some time to code. I only finished all of them on day 3, by which time I still had zero content. I had to crunch quite a bit in the 4 following days, rushing out music, sounds, shaders and sprites, despite cutting a lot of content, even including the final boss that would have justified my game’s namesake (which is why it’s called RedShift Prototype, instead of just RedShift).
In the end, a lot of the game isn’t quite satisfactory, and I regret being unable to fully present to you what I had in mind. I never expected it to place #1, but to my surprise, people seemingly liked it despite its copious failings. Again, before I move on to more technical stuff, I’d like to thank you for reading this far.
While it might seem magical if you don’t know what to look for, the rewind mechanic is actually very trivial to implement. In a sense, I didn’t even implement it. Rather, I allowed it to happen.
If that didn’t mean anything to you, then consider an emulator of an arcade machine, or a classic console. Emulators often have this save-state feature, which allowed you to return completely to any early point in time: audio, graphics, game state, everything. Does this sound familiar to you? Yes.
RSP simply makes 60 save-states every second. That’s it.
Now, unlike emulators, modern game engines don’t usually support save-states, for a good reason. In an emulator, a save-state is just a snapshot of the RAM and registers of the virtual hardware. Making and restoring one is as simple as memcpy
. That’s easy, fast, and bug-proof. Modern engines have much, much more going on internally, making such instant save-states infeasible to generally implement. That’s why I had to allow it to happen myself.
What I did is:
memcpy
most of the state, speeding the save-state process up drastically, enough for it to happen in 60fps, even on low-end machines.With the help of high-level features in Rust, the Godot Rust bindings (full disclosure: I maintain it), and a heavily modified version of hecs, it was fairly easy to code the game considering all the constraints. Once the rewind itself is working, the rest of the game is made normally, since the mechanic works outside the game logic. I could easily use the intuitive model of state and mutation in enemy / player behavior, without fear that rewinds might somehow become screwed up.
While time reversal itself is not a new idea, it was a lot of fun implementing it.
hecs
for some while, I’m increasingly feeling that it’s being outgrown by my needs. I managed to patch it enough to fit the requirements this time, but eventually I might want do a hard fork of it or even reinvent my own wheels. Who knows?Despite previous experience in game jams short and long, time management is still one of my weakest points. I really need to learn how to plan my time better, not just for jams, but also for longer projects. And while personally I’m not very satisfied with the game, I’m very glad that people likes it nevertheless.
Thank you for reading to the end.