Coding into the Void

Coding into the Void

A blog that I’ll probably forget about after making thirty-five posts.

2020 Retrospective: An Aimless Path

I’d set a goal for 2019: 12 games in 12 months, which I more or less accomplished as long as you don’t look too hard. I set absolutely no goals for myself in 2020. Here’s how it shook out.

Development Timeline

This timeline comes courtesy of the far future of mid-2022!

Four Block Drop: My January Project

If you’ve read my 2019 retrospective, you’ll know that I started work up again on Four Block Drop back in December, much to the detriment of the projects that I planned to put out in 2019. In 2019, I was focused on getting a good-feeling modern Tetris game, with the standard rules required to comply with the Tetris standard. In 2020, I wanted to experience the wider texture of the Tetris space. Gameboy Tetris is wildly different from modern Tetris (although I did support, with limited accuracy, a version of that mode).

But there’s also NES Tetris. And Tetris The Grand Master (TGM). And what about the first version of Tetris? All of these have a different feel, and it’s worth giving most of them a shot. You won’t see the intensity of play in modern Tetris that you would in TGM games. TGM gets to be a fast and highly strategic game, which requires thinking on your feet and quick placement.

The Arika Rotation System (ARS) is more restrictive than the Standard Rotation System (SRS), in a way that prevents more complex moves, but also requires that the player be more thoughtful about their moves.

Another small change in TGM that makes a large difference is the instant drop. In standard games, it’s a hard drop: once the move is made, the piece is instantly locked down. In TGM, it’s a firm drop, which allows you to move the block around after the block hits the ground.

The soft drop switches roles, with it becoming locking in TGM. It might sound strange if you’re used to standard Tetris, but I found that it felt good to play with. There’s a speed boost from being able to hard drop and then tweak the position.

There are many other interesting differences (IHS and IRS, among others), which I suggest that you look into if you’re interested. I’m far from a Tetris expert, so other sources will have more accurate information. Besides, this is isn’t a Tetris blog post!

I also put a lot of effort into refactoring it. I rewrote the input system, supporting controllers and giving me a base that I could use in future projects,1 and completely separated the game model out from the rendering layer by sending game logic updates through messages to the layout layer. This has its plusses and minuses, but it greatly cleaned up both my logic and layout code.

My interest in Four Block Drop tapered off while I was trying to add support for torikans2 to my game. Not content to hard code a bunch of conditions in, and hung up on the idea of customizing game modes and being able to export and import them, I decided I wanted to implement my own scripting language.3 This wasn’t really out of hubris, more that I thought it’d be fun and lighter weight than just trying to embed the entire Lua runtime.

Because of the limited scope of the language, I could do shortcuts to enable more concise representations of the rules. So, for example, let’s say you wanted to check if 3 minutes and 25 seconds had passed before the level 500 was reached (a torikan condition used in TGM 2) and, if so, end the game once that level is reached. Here’s how it might look in regular typescript:

let timeLimitMet: boolean;
let levelMet: boolean;
let timeLimitMetFirst: boolean;

void onCheckTorikan(score: FBDScore) {
    timeLimitMet |= score.time >= 3 * 60 + 25;
    levelMet |= score.level >= 500;

    // If levelMet was set for the first time after timeLimitMet 
    // had been true, time limit was met first.
    timeLimitMetFirst |= timeLimitMet && !levelMet;

    // Return true once the required level is met.
    return timeLimitMetFirst && levelMet;
}

Wordy. Annoying for a common concept (torikans would become a hassle to implement). What if… we had a before operator? It would maintain the state within itself.4 Instead of all that, we would just have:5

void onCheckTorikan(score: FBDScore) {
    return (score.time > 3 * 60 + 25) before (score.level >= 500)
      && score.level >= 500;
}

Simpler. Less boilerplate. The scripter needs to worry about less global state. Sure, it’s a “bad idea”, but it’s helpful in this context and it’s something I haven’t seen in other languages.6

I actually have a working version of this in my code, and it’s what determines the game win logic. In the end, however, I got bored of working on it before conditionals and the like were added, so it’s not fully fledged, and led to me losing interest in working on FBD.7 The last commit for Four Block Drop in 2020 was on January 19th, and it was optimistically titled “Started on return statement.”

What I Learned

  • Pros and cons of separating game logic from the display code.
  • More about Tetris than I ever knew existed.
  • A considerable amount about controller deadzones.

A Colossal Interruption

In early March I started working from home. In order to get some more social contact, I decided to join a few discord communities. In early March I had played the Haunted PS1 Demo Disc 2020, which was absolutely incredible. It really increased my appreciation of what a well-done PS1 aesthetic can do, although I had long liked the aesthetic of games that capitalized on a low poly art style, like the Trails in the Sky games and else heart.break(). Since they had a discord, I decided to join it on April 7th. Two days later, the Haunted PS1 Wretched Weekend jam began.8

It was a weekend jam, and I was inspired to make a game with a colossal, unkillable presence. You’d have no chance of fighting it, or even interacting with it. Humanity had all but adapted to it.

In contrast to previous games, it would have a static level design. I’d only done this before in The Walk & Talk,9 with all of my other games being procedurally generated, levelless, or arcade-type. Since it was a two day jam, I didn’t have much time to figure out or look up a good process for level design.

I made a bunch of 1x1 quads, and then copied them to form my walls, my floors, and my ceilings. This was a pain and not well-optimized, but it worked. I created a fleshed interaction system to go with text boxes and interactions that I pulled from Poetry Without Motion.

I had grand plans to model all of the assets in the game, but most of the items in the game ended up being from a free asset pack. With the constraints being so tight, I didn’t have time to figure out an asset flow, and figured it was better to have all items in a consistent style instead of a hodgepodge of appearances.

The texture work is rough, even by PS1 standards. The staircase and elevator sections were perhaps the least appealing, arguably downright ugly.

I created an item interaction system, and populated various items with a slew of lines that the player could read. In order to slow the player down, there were some items that the player needed to find that were randomly placed throughout the apartment. To hopefully avoid the player missing an interactable and therefore getting stuck, it will give the item to you if you search a minimum number of its potential hiding spots.

The core gimmick is that there’s an unwritten time limit, punctuated by increasingly loud footstep sounds and increasingly strong screen shakes every five seconds. If you don’t make it out in five minutes, you’re toast. This should be sufficient for all but the slowest player.

If you’re at all interested, you should give it a shot (either with the jam or the much-polished post-jam version). As I said, it’s only about five minutes long.

It was interesting seeing people talk about the themes in it: some people were talking about it representing the social isolation the player was feeling, with others talking about how the colossus was a fictional metaphor.

I know it’s a somewhat gauche, but the following is the message that I intended, which I’m writing out here so that I can refresh my memory on the details. The colossus was a metaphor, but in-game it’s all quite literal. In the world of the game, there really is an unkillable colossal creature just meandering across the planet, and the only recourse is to evacuate everything in its path.

Is it more than a little bit implausible that the player character would manage to sleep through a huge city-wide evacuation? Sure, but join me in fiction.

The story that (hopefully) the player can piece together is that their apartment was burgled in the past, and it had a profound effect on the safety that they and their former flatmate felt in the apartment. The flatmate moved out at some point, but the player is still trying to make it work.

If it feels absurd that the player is worried about their apartment being burgled when there’s an unkillable colossus roaming about, it was intended to be, but it also was intended to comment on the ability of people to adapt to new situations.10 Things that seem miniscule in comparison, like a burglary, can end up taking much more of your headspace. It’s like how you’d probably drive 10 minutes to save $25 on a $26 pen, but not $25 on a $25000 car.

The colossus, of course, since it was 2020, represented the pandemic, and the burglary some relatively-trivial matter that was being talked about more than the pandemic.11 The player not knowing their neighbors, of course, could be likened to the limited social contact of sheltering in place. Most of these weren’t things that I intended to say when starting down the course of the game, but natural evolutions as I was writing out descriptions for the apartment.

I finished the project with time to spare, as I generally try to underscope on jams so I have plenty of time to test and upload the build. I was happy with the results. Still, I felt like there was the opportunity to do it better.

After the jam had finished, I continued work on A Colossal Interruption. I found out about a plugin for Blender called Sprytile, which allows you to create tile-based scenes: a perfect fit for what I’d been working on. I redid the environments using Sprytile, redid a few of the textures, modeled out items for the inventory, and put out the new version.

The game was surprisingly popular in the jam, and is by far the most popular game I’ve published. At one point it was the 15th most popular game on itch, which was genuinely surprising. People on itch love indie horror games, apparently, as most of the top 15 at that point were games from the jam. I also assume my game icon was visually appealing and drew people in, but I have no evidence for that. As of today, it’s gotten just over twenty-five hundred downloads, which I’m sure is minor for most games, but feels great for me.

Top 15!

Working on the post-jam version of A Colossal Interruption really drew to the forefront how much I was just copying code from one project to another. I wanted to make a shared library that I could import using the Unity package manager. I set about on this, but I wasn’t able to find purchase with it, and ultimately it led me to drop working on game dev until June.

The jam ran from April 9th to April 14th (with the stipulation that you make it within a 48 hours period during that time). I ended up publishing it a day and four hours before the deadline. My post-jam work continued for about a month, until May 12th.

What I Learned

  • Some basic texture work.
  • Two ways of making tile-based levels in Unity.
  • Reinforced the joys and downsides of using MonoBehaviors to store logic instead of hard-coding it all.
  • The lure of a shared package for Unity.
  • How awesome the Haunted PS1 community is.

The Abyss of Dastroreth

Despite falling off from game dev, I still remained active on the HPS1 discord, and one of the members talked about a jam he wanted to run, the Two-Minute Horror Jam. It would start on May 13th and run for two months, until July 13th. The concept of a horror game only lasting two minutes was appealing, and I wanted to participate. There was only one problem: I had to think of an idea.

The first idea that came to me was as such: a third-person game where you wake up in a bedroom and start wandering around. You can exit into the hall and explore there too. As you explore, the camera would begin pulling up farther and farther, revealing that you were in a large maze made up of similar rooms. The camera would pull out so far that it was clear that it seemingly went on forever.

I still think this is a neat idea, but there were a couple problems of it. First and foremost, it required a lot of art, especially the character model. Having one that didn’t look out of place or janky would require a great deal of luck on my part. Secondly, and this is what really killed it: I realized it was incredibly similar to the ending of another indie game, one that I really liked. While it’s in an entirely different context, it still made me toss aside the idea.12

The next idea involved an astronaut on a space station (think the ISS). You’re alone and have to do an extra-vehicular repair to fix some mechanism on the outside. As you go to do the repair, something explodes, knocking you back. Your tether to the space station snaps, and you end up flipping end over end as you see the space station recede in the distance. Scary concept.

There were a few problems with this:

  1. It’s hard to put a two minute cap on something that requires input.
  2. It required a lot of art.
  3. If I wanted to be at all scientifically accurate, I’d need to do research and probably change a bunch of things.

I was on the edge about this one: I felt like I could source a lot of the textures and go for a PS1 style to make the assets quickly, but it felt somehow ghoulish to turn someone’s death during a space walk into a game. I felt certain that at some point someone would have died during a space walk. It turns out, no, no one has. In fact, only three people have died while in space. This allayed my reservations somewhat, so I started work on the project.

I’d spent somewhere around an hour on a project before my final idea hit me. I don’t know what caused it, but I was revisiting Strangethink23’s work, mostly through YouTube videos, as they’ve since removed them from download. Strangethink’s work, particularly Strange Habitat, is some of the art that comes to mind often when I’m thinking about game dev.13

I was watching someone play Strange Climber14 and noticed how the procedural generation, despite creating intriguing and novel shapes, was made up primarily of simple shapes attached together. This was in stark contrast to my procgen style, which tends to focus far too much on the granular.

I wanted to make some otherworldly tower, filled with messy and abstract procgen. The gameplay and timer elements of this were easy: you’re attempting to outrun a rising pool of gasoline.15 Your goal was a teleport far, far above you, and you had to use first person platforming16 to escape. Horror might be overselling it, but most of my horror games are more “you’d be scared if you were in this situation” and less “actually scary”. In other words, they’re not very good horror games.

In honor of its clear Strangethink influence, I gave it the codename Strange Platformer.

The algorithm I used was simple, and around 40 lines long:

// Create a path using floors.
for (int i = 0; i < NumFloors; i++) {

    // We'll start in the middle and with a climbable platform, and then
    // go around based off of that. I may also want to explore using multiple
    // connection points instead of going off in one direction.
    Vector3 currentPosition = transform.position;
    // The + 0.01f is a terrible hack to prevent z-fighting on the floor.
    currentPosition.y = i * FloorHeight + 0.01f;
    Quaternion currentRotation = Quaternion.identity;

    int elementsOnFloor 
        = Math.Max(MinimumElements, ElementsOnFloor + (i * ChangePerFloor));
    for (int j = 0; j < elementsOnFloor; j++) {
        TowerElement element = RandomElement(rand);
        GameObject placedFloor = Instantiate(element.Prefab, this.transform);
        SetScale(element, placedFloor, rand);
        TowerFloor towerFloor = placedFloor.GetComponent<TowerFloor>();
        generatedObjects.Add(placedFloor);

        List<Transform> connections 
            = rand.PickFromList<Transform>(
                towerFloor.FloorConnectionPoints, 2).ToList();
        Transform initialConnection = connections[0];

        // Find where we're going to connect the current floor to.
        placedFloor.transform.rotation = currentRotation;
        placedFloor.transform.position -= initialConnection.position;
        placedFloor.transform.position += currentPosition;

        // Find a new connection point for the next floor.
        Transform terminalConnection 
            = rand.FromArray(towerFloor.FloorConnectionPoints);
        currentPosition = terminalConnection.transform.position;
        currentRotation 
            = Quaternion.Euler(terminalConnection.forward) 
                * RandomDirection(rand);

        if (Connector != null && j != elementsOnFloor - 1) {
            GameObject connector = Instantiate(Connector, this.transform);
            connector.transform.position += currentPosition;
            generatedObjects.Add(connector);
        }
    }
}

Basically, for each floor, start out with one seed piece, and randomly weld a piece onto the last placed piece at a random junction and angle. Simple, and yet it generates a climbable tower in every case that I’ve tried.17

Since I wanted the lion’s share of the time to be in climbing, and I knew most people would take multiple attempts, I didn’t want to spent much time on setting the scene. At the same time, I did want to give the player some context as to what they were supposed to do.

I settled on having three lines displayed in the center of the screen for the game start, game lose, and game win conditions. It adds a nice frenetic pace to the game and doesn’t get in the way too much. To add to the otherworldly feel, I decided to have the footstep noise be drum snares. I like the effect, but I it didn’t work for everyone.

The hardest issue that I encountered, and one that I didn’t fully solve, was having the tower’s texture be interesting-looking but also easily readable, even in shadow. It does have a fleshy look that I like, but in the end, it can be a bit hard to read while you’re frantically platforming.

I worked on The Abyss of Dastroreth from June 25th to July 5th, one week and 20 hours before the deadline, with one post release patch on the 7th to add in some accessibility options.18 It got a fraction of the views and plays that A Colossal Interruption got,19 which I put down to three factors:

  1. The cover image isn’t appealing
  2. This was a less publicized jam (fewer games got on popular)
  3. Not a standard horror game

Regardless, a YouTuber that I enjoy watching, MrKravin, played the game as part of a compilation here. It popped up in my feed, and I saw that it was the two minute horror jam. When my game popped up in there, it was a pleasant surprise. Thankfully, he didn’t seem to dislike it too much.20

I’m proud of The Abyss of Dastroreth. I enjoy playing it, and the rising fluid makes it so you have to play at a frantic pace. The skybox looks great, and I like the simple procedural generation that I did. Conceptually, I was going for a kind of hellish experience: brutally difficult and frustrating. I had pictured it as part of a sort of “gamer hell”21 series of games.

In between the jam release and the accessibility option release, I finally figured out how to set up a Unity git library, which would become one of my next big projects.

What I Learned

  • A simpler form of procgen.
  • Fun with shaders!
  • An exercise in minimalism.
  • It’s both scary and exciting to have a YouTuber you like play a game that you’ve made.
  • How to set up a Unity library.

KHPackageCore (July 6th - July 28th)

I’d finally done it. I set up a package that could be loaded through git.22 It was much smaller originally, starting with only my build script and some simple animation curves. I quickly added my menu generation code23 and slowly worked on transitioning my scripts over to it. This was concurrent with my next project, codenamed Strange Traveler.

What I Learned

  • How to set up a Unity library (duh).
  • Unity libraries can’t depend on Unity packages, so Rewired and other integrations still need to be copied over.24
  • It’s both a blessing and a curse to have a Unity library, as you always want to update it when returning to an old project. Changing the API suddenly makes returning to old projects much more time-consuming.

Strange Traveler

It’s probably obvious based on the name whose works this was influenced by. I was enraptured by the cities generated by Error City Tourist, another Strangethink game, but one I did get to play. It’s a little bit quirky, but there’s a monorail that stretches endlessly across the world that is just incredible. An infinitely generating world with public transit!

I wanted to do that, but, and here’s where I get in trouble, not just in one straight line—weaving across chunks of land. My project, codenamed Strange Traveler, was intended to be a continuation of the “gamer hell” theme. You would be traveling through procedurally generated towns and cities, running from NPCs that would try to kill you at every opportunity.

The conceit was to be that, after escaping from The Abyss of Dastroreth, you appeared here, without weapons. The inhabitants of this area know the havoc a player can wreak and are determined to scare you away. They could do this because notes from other games are sent to this strange land.

The end of the Two Minute Horror Jam aligned nicely with the next HPS1 game jam, the Summer of Screams. It started on July 17th and ran until August 31st. The optional theme, architectural horror, aligned relatively well with my concept. A good chunk of time for making a game. However, I went into it knowing that I planned to participate in the next LOWREZJAM, which ran from July 31st to August 16th, bisecting the Summer of Screams in two.

I quickly realized I’d overscoped. Multiple enemy types meant a lot of art and the challenge of pathing across procedurally generated terrain seemed far out of scope for the month I had to play. I axed all NPCs from the game, and pivoted from the notes being notes from other game worlds to notes from people who had visited this empty abyss before you.

The level generation was complicated: I wanted to generate procedural buildings, but with monorails that connected various areas together. In essence, there’d need to be multiple procgen algorithms cooperating to make sure they didn’t step on each other toes.

The lessons I learned earlier about simple level generation were quickly forgotten. I made this one as complicated as ever, combining walls and floors and stairs to make something coherent and human.

I’d purchased a FPS controller asset in a sale, hoping to use its interaction and moving platform capabilities to make development go faster, but even setting up the controller was overly complicated. I spent as much time fighting the asset as I did initially implementing it. This, I suspect, make me more reluctant to return to the game.

When LOWREZJAM began, I put this aside. I didn’t return to it in 2020.

Why it Failed

  • FPS controller asset I purchased ended up being too finnicky to use correctly.
  • Complicated, challenging procedural generation.
  • Lack of enthusiasm to return after LOWREZJAM.

What I Learned

  • First serious attempt at using the HPSXRP in a game.
  • I find it difficult to keep focus during long jams.
  • If you’re going to take a break from something, leave it in a good state.25

What a Card!

I’d participated in LOWREZJAM the previous year, and I had a strong idea for a game that I wanted to do: WarioWare-like microgames using only a set of playing cards. LOWREZJAM limits you to a 64x64 window, so space is at a premium. I needed microgames that I could explain in 10 words or less, which provided a fun limit on the type of games that I could use.

LOWREZJAM is a ranked jam. The previous year I’d done a walking sim, so unsurprisingly I didn’t score that well. Mysteriously, though, to me, my rating in the authenticity department (does it adhere to the 64x64 resolution restriction) was a 4.467. Now, I was using a render texture with a resolution of 64x64, so it absolutely adhered to that restriction.

Well, okay, I thought, I’ll just do something that really adheres to the spirit of it. Clearly 64x64. No transparency.26 Really drive home the adherence to the resolution part of it. Also, I wanted it to be exclusively art that I made myself.27 LOWREZJAM 2020 ran from July 31st to August 16th, so I knew I’d have plenty of time to get the infrastructure up and running, with much of my time being devoted to game modes.28

As expected, I was able to get a rudimentary game with card assets up and running within a day. I had envisioned game modes as a sort of legos. There were different frameworks for game modes that I’d develop, like scrolling cards, monte, or dodging cards. I’d pass different conditions into them, like what cards were generated, which needed to be selected/dodged, and how they moved. This let me expand around 10 game modes29 into 51 microgames of various distinctiveness.

I finished it over four days before the deadline, planning to move back to Strange Traveler. I didn’t. Part of participating in a scored jam is rating the games of the other participants, so I played most of the other games submitted to the jam. My sister also participated in this (her first game jam!), so it was fun to help her navigate the game dev experience.

You know how I said my goal was to score higher than 4.467 on authenticity? Well, I did. I score a 4.5. On a game that made it painfully obvious that it was 64x6430. I found out that some people were using that to also rate the graphics, which was strange, because there was also a graphics score. Very frustrating.

The combination of spending the time rating other people’s games, annoyance at the strangely low score,31 and the broken state I left Strange Traveler in worked together to dissuade me from working on game dev. I don’t think I returned to development until I went back to Four Block Drop in late January 2021.

What I Learned

  • Scored jams can be incredibly frustrating.
  • I really shouldn’t care at all about my score.
  • But I do more than I should.
  • Very strictly attention-based games are bad for streamers.

At the End of it All

2020 was certainly a slower year for game development for me, as I only finished three games32 as opposed to the prior twelve.33 Still, I found a great community and learned some valuable skills. With KHPackageCore, I’d build a strong foundation for me to get certain components of games working quickly, including my most hated task, making and hooking up menus.

2020 contained my most played game to date, A Colossal Interruption, and the one I think is the most fun, What a Card!. Given what else was also going on in 2020, I think it’s a pretty good showing.


  1. See here for my posts exploring that. ↩︎

  2. A torikan is when the game decides that you aren’t doing well enough, and gives you an early game over screen. Not a loss, per se, but more an acknowledgement that someone playing at a lower level of play should still be able to reach the end screen. ↩︎

  3. Famously a bad idea. ↩︎

  4. This is certainly a bad idea in most contexts. Example hangups developers might have: What’s the lifecycle of this state? Why should I even know that it stores state? These questions are less relevant when working clearly game-instance scoped in contexts and in the context of short, functional scripts. ↩︎

  5. Not my scripting language syntax, but instead in typescript for ease of comparison. For comparison with my language, the line would look like return ($$THIS_TIME >= 3 * 60 + 25) before ($$THIS_LEVEL >= 500) && $$THIS_LEVEL >= 500);. In this case, the $$ represents a constant that I pass into the runtime. ↩︎

  6. Probably because it’s a bad idea. ↩︎

  7. A blessing and a curse. ↩︎

  8. This narrative excludes a 3D platformer project I’d spent approximately one hour of work on. Interestingly, my interest in creating a 3D platformer (which is so far out of my wheelhouse it’s almost absurd: 3D assets and level design are certainly not my forte) was triggered by playing Macbat 64, a bite-sized 3D platformer made by Sciatro, who coincidentally had created Tasty Ramen for the demo disc. ↩︎

  9. Calling that level design is a bit of a stretch, since it was based on schematics of the real life West Wing, but I did have do implement NPC movements and timings. ↩︎

  10. This may have been a bit optimistic, but I was less than a month into working from home at that point. ↩︎

  11. I want to say it was packages being stolen from porches, but I could be misremembering. Part of the problem of writing a retrospective almost two years later. ↩︎

  12. Although I still think it’s a fun, neat concept. Writing this section made me want to revisit it. ↩︎

  13. Strangethink’s procedural generation, Tom van den Boogaart’s Bernband, and Zykoveddy’s Electric Highways are the biggest influences on my work or, at the very least, what I dream of making. ↩︎

  14. I’ve since managed to acquire a copy of Strange Climber and play for myself. Interestingly, I think it may be designed so you can’t beat it, although perhaps that’s just a bug that I encountered. ↩︎

  15. Fun fact: humans don’t float in gasoline. ↩︎

  16. One weird trick to make 90% of gamers hate your game, but me love it. ↩︎

  17. And if it isn’t climbable, you probably won’t be able to figure that out in the two minutes you have to climb. A perfect system. ↩︎

  18. Slowing down or turning off the gasoline, and an easier tower configuration. I would’ve liked to add a double jump, but that would’ve required a great deal of extra code. ↩︎

  19. Just over 250, which still isn’t bad. ↩︎

  20. Although if he had, it probably would have good practice for watching videos like that in the future. Like immersion therapy. ↩︎

  21. Yes, I know that sounds cheesy. ↩︎

  22. I assume it worked at this commit. I don’t remember and don’t care enough to test it. It works now, at least. ↩︎

  23. Yes, this menu generation code. ↩︎

  24. Now that I think about it, I’m not sure they need to compile in their library form, so I may be able to separate those out and just only import them to a project that already has Rewired in it. ↩︎

  25. Advice I could still learn to follow. I have two unfinished games from 2021 that I’ve left in a broken state, but I’m getting ahead of myself. ↩︎

  26. I use a dither pattern for fade effects. ↩︎

  27. Normally a mistake, but this was a reasonably-scoped amount of art for me. Plus, I’d gotten Aseprite, so it was fun to mess around with pixel art. ↩︎

  28. I’d done a similar project years back, and I was able to get basic gameplay up and running within a day. ↩︎

  29. If you’re being generous. Around six if you’re not. ↩︎

  30. You could even play it at the original 64x64 resolution! ↩︎

  31. Unreasonable and self-defeating, but it was how I felt at the time. ↩︎

  32. Although I ended up rewriting most of Four Block Drop, so you could arguably include that as a new game. ↩︎

  33. Depending on how you’re counting. ↩︎