About
Rats! is a prototype 3D action game using a ray casting software renderer (like Wolfenstein 3D). Rats! began as an attempt to produce a working game prototype within a month.
In Rats! you take control of a mouse hunted by malicious rats. Your goal is to collect treasure, eat lots of food, and stay alive!
Downloads
I’ve done my best to support both Windows 11 and Debian Stable (Trixie). The Windows variant will probably also work on Windows 10.
| OS | Package |
|---|---|
| Windows 11 | rats.x86_64.0.1.0.windows.zip |
| Debian Trixie | megatech-rats_0.1-1.trixie_amd64.deb |
The source code for Rats! is available on GitHub.
System Requirements
| Requirement | Minimum |
|---|---|
| OS | Windows (10, 11) or Debian (Trixie) |
| Processor | 64-bit Intel or AMD (x86) |
| Memory | >= 4 GiB |
| Graphics | Support for OpenGL 4.5 or newer |
| Storage | >= 1 GiB |
Controls
Keyboard
Rats! uses mostly conventional controls. Since this is a prototype, there are some weird extras (like quitting and rotating).
| Key | Action |
|---|---|
| Q | Rotate Left |
| E | Rotate Right |
| W | Walk Forward |
| A | Strafe Left |
| S | Strafe Right |
| D | Walk Backward |
| Tab | Toggle Automap |
| ` | Toggle Developer Information |
| ESC (Escape) | Quit |
| Alt+Enter | Toggle Fullscreen |
| Right Control | Release mouse pointer |
Mouse
Rats! supports horizontal mouse look. The camera cannot move vertically.
Attacking works by facing an enemy and clicking the left mouse button.
| Button | Action |
|---|---|
| Left | Attack |
Tech
Rats! is written in C++23 using OpenGL 4.5, SDL3, Miniaudio, Boost.Iostreams, WebP, and PCG Random. The game is single-threaded (including audio) and uses a custom software renderer.
For assets, Rats! supports only WebP and MP3. During initial development, I decided to pick exactly one format for each type of asset. I chose WebP for images because it produces good compression and the decoding API is simple to use. The choice of MP3 was even simpler. Miniaudio decodes WAV, FLAC, and MP3. I didn’t want to add another dependency to decode audio files, so I went with MP3.
The Rats! renderer is, I think, pretty similar to Wolfenstein 3D. The renderer casts rays into the world starting at the camera (player) position. Each ray either intersects a wall or terminates. Then the renderer draws the appropriate texture mapped ceiling, wall, and floor pixels for the column of screen pixels corresponding to the ray. After the world is rendered, Rats! iterates through sprite entities (enemies and pickups). These get drawn based on whether or not they are within the player’s field of view and use a depth buffer to cull pixels that are fully behind another object. Rats! also applies a per-pixel distance based lighting effect. Rats! renders its output at 320x180 pixels and scales to the viewport size. The renderer can support higher resolutions, but Rats! is set at 320x180.

Ultimately, the rendered images are handed off to OpenGL. OpenGL is responsible for scaling the image, correctly encoding colors to sRGB, and putting it on the screen. In testing, I encountered some configurations that didn’t support sRGB framebuffers, so in those cases I do the color and image transformation in a shader program.
Besides the world ray casting operation, the software renderer also supports alpha blending, lines, rectangles, animated sprites, full frame color filters, and atlas-based text rendering. Except for blending, these techniques are used to render the HUD and automap.
For audio, Rats! supports 32 simultaneous sound effects and a background music track. This is mixed by Miniaudio and then sent to SDL3’s audio subsystem. The audio system is synchronous with the rest of the application and not on a second thread.
The world of Rats! is generated using Prim’s Algorithm followed by a second pass to carve rooms over top of the resulting maze. After carving the world structure it also places pickups and enemies throughout the world. Enemies in the world can navigate to the player using breadth-first search. The world tracks a variety of information on a per-cell basis including whether or not the player has seen each cell. At the player’s request, Rats! can render the world to a map (the automap) showing the player’s position and orientation from a top-down perspective.
Jank
Artisanal Jank
Some of what Rats! is doing is archaic or weird on purpose.
The 2-bit color palette is one example. I chose to limit the game’s palette mainly to make it easier for me to draw sprites and textures. The actual images are all grayscale and Rats! maps each gray level into the palette during loading. Originally, I wanted to use photo textures (captured with a proper mirrorless digital camera and not my junky telephone). I did take these photographs. However, I found processing them to be relatively difficult. They simply didn’t tile particularly well or lose enough detail from being downscaled for my taste. I settled on just drawing everything by hand using GIMP.
The choice to use affine texture mapping is another example. I certainly could have done perspective correct mapping, but I like the way affine mapping looks. I grew up with a PlayStation, there’s no helping it. I’m not a huge fan of the sort of retro-game filters many projects on commercial engines use. I don’t think it really captures the look of the PlayStation properly, and the Nintendo 64 (the other system I had at that time) certainly never looked like that. I was a spoiled kid I guess.
Like with the graphical content, I’ve chosen to use relatively compressed MP3 files for sounds and music. This is an active choice too, but I don’t think it really captures the effect I wanted. I was hoping for something that sounded a bit more like Duke Nukem 3D. I’ve simply chosen lowest bitrate format Tenacity would give me and occasionally applied some distortion. Like with the image assets, I’ve made all of the sound effects and music in this release myself. Can you tell I’m not a musician?

Prototype Jank
The bottom line, though, is that Rats! 0.1.0 is a prototype. It’s some pieces of a game stuck together to show that I can build something like this. This isn’t a tightly designed or highly optimized machine (which is what I would like to imagine I would make if I had the resources). It’s a prototype.
So, there’s some real jank associated with that too. Not everything about Rats! is weird because I’m a weird guy who likes old computer games. Some of it is just me cutting corners or making decisions that got the game working rather than doing what, in my opinion, is correct. If you play with it, you’ll probably find this stuff.
Here are a couple of examples. First, when you reach 200% HP if you sit on top of a health pickup the sound effect will play over and over. The fix for this is a simple conditional check, but I omitted it. I felt, for a prototype release, this was a fun little imperfection. I simply forgot to write the check in originally. The same effect can be heard if you press against a wall or enemy repeatedly. Second, enemies can spot you right as the game starts. I probably should have given the player a small safe zone during world generation, but I didn’t! Oops! The result is you can get attacked right when the game loads which is pretty disorienting. It happens fairly often too.
I think the worst oversight is the lack of a complete eight-directional sprite for the enemy. I only drew two directions (front and back) because it was easier and faster to do. Unfortunately, there are lots of orientations where this makes an enemy look like it’s facing you (or away from you) when it isn’t. This makes it really hard to tell when or why an enemy will detect you. The actual detection scheme is simple. If you bump into an enemy they detect you. If you attack an enemy they detect you. Otherwise, they scan an arc in front of them. If you fall within their field of view along that arc they detect you.
There’s plenty more where that comes from, but I’ll leave it to you to discover.
Thoughts
The last couple of years have been pretty hard on me. Probably, because I’m a wimp. I’ve been teaching and did a 10 month stint as a software engineer for a startup company. The experience has been, on the one hand, pretty much constant crunch to write lessons or build features (depending on the day) and on the other hand nearly constant waiting on others to make decisions (usually the decision to commit resources). Admittedly, I’m a death schedule kind of guy. I’d love to have worked on Quake. Still, it’s been difficult and it remains difficult.
My conclusion from the experience has been that a lot of software is too palatial. It’s too big, impressive, and sophisticated. Often, complex technical solutions arise where arithmetic would suffice. It’s this feeling that gave rise, at least in part, to Rats!. I think the sword of palatial software cuts two ways. In one direction, it destroys by making the software too complex to manage. Everything is a diagram in an Nvidia SIGGRAPH presentation. In the other direction, though, it makes software much too concrete. When I was younger, there was always a little question about what was really in a game. Could you get Mew in Pokemon? Sort of. Could you find the Key of the Twilight in .hack://Quarantine? Not in any way that matters. I really think a good game should be a little murky and dream-like at the edges. Maybe, a word processor should be too.
So, I want Rats! to at least be tangential to that idea. I want to keep it simple, even if I continue to work on it. It’s tempting to write, here, some kind of screed or rant about my philosophy. I think it would stand better on its own though. There’s nothing I can say about my distaste for this popular framework or that popular game that isn’t better said by just working more on Rats!, God dammit! I want to make things that prove me right or wrong. I want to prove that I mean it when I say that, “shipping is the feature,” or, “you have to come into contact with the enemy.”
Moving on, the inspiration for Rats! was pretty simple. I came up with the idea while working on another project which was inspired by Stratego: Legends. Stratego: Legends is a discontinued version of Stratego that sort of combined the classic variant with role-playing and trading-card game mechanics. The game was discontinued pretty quickly, but my dad and I played it a good amount. I remember playing it in a slightly uncomfortable hotel room at the River Inn in Big Sur. I think, the board game was supposed to be a way to get me to engage with the sort of gadget detox feng shui of that trip. I always had trouble with these types of holidays as a kid because of the separation from my beloved PlayStation. In hindsight, it wasn’t so bad if you could stomach the hippie shit coming from all sides. My dad, once, insisted that Big Sur was all about, “edges,” and I still don’t know what the hell he meant.

On that same trip, I was reading (or being read because I was a spoiled little shit) Lord Brocktree. This was the first Redwall novel I’d read or perhaps the second. I had kind of put Redwall out of my mind entirely until this memory came to me. I miss those books and their fascination with cordial though. My feeling was, that a setting like Redwall is an underused setting. I think, perhaps, because it’s very child focused in its temperament or simply because everyone gets a little anxious about anthropomorphic animal characters these days. Rats! was originally meant to channel Redwall. Besides Redwall, I was also inspired by games like The Elder Scrolls: Arena and Shadowcaster. The inspiration for the name Rats! was, “It’s Green and Pissed,” a proposed name for a game by Id that got passed over in favor of Wolfenstein 3D. I’m not totally committed to Rats! as a title, but I feel like it’s a good working name for now. It’s snappy and straight-forward.
My actual original concept was much larger and more involved than this prototype. Originally, I wanted a narrative, interactive spaces, different sky modes (ceilings for interiors and a cylindrical sky texture for outdoor areas), properly designed levels, multiple types of enemies, and so on. Most of this has been cut to get this prototype into contact with you. Originally, I wanted the player to be a harvest mouse fighting an order of evil rats (and other creatures like bats) who aligned themselves with, “the old god,” (a large cat). That’s the origin, for example, of the enemy’s look in this prototype. The mark on their front side is meant to be a cat’s paw, by the way. I also wanted a proper collision system based on ray or shape casts rather than the current grid based occupancy test. Almost all of this is on the shelf for the moment.
If I find the time to keep going on Rats! I’ll probably end up gutting a lot of the OpenGL infrastructure. I really just have an incredibly low tolerance for loosey-goosey APIs like OpenGL where things happen behind your back or have, “spooky action,” of any kind. I chose OpenGL because it obviates a lot of the device selection hocus-pocus required to use Vulkan. I think Vulkan 1.0 (and certainly Vulkan 1.4) would cover all of my needs though and make me feel less anxious.
Beyond that, I really do want to expand the game artistically. I want to add proper collisions in so that I can start to have more complex interactions and entities. A lot of the game as it is now will need refactoring to achieve that. The current organization, unfortunately, is totally unsustainable. With better organization I can start to build a more sustainable landscape of tools too. The more I write about it the more I start to slip into the anxious ambition of being 10 or maybe 12 years-old and designing computer games in my head. It’s a dangerous space to be in, but one I’m desperate not to lose all the same.
So, I’ll leave it there. I’ve got to get more work done. I hope that if you play Rats! for a little bit you can see what I was trying to achieve under all the jank.
ずるずるずるずる。
Credits
Programming, Art, Sound, and Voice Acting
Alexander Rothman