Postmortem: Dice Tower

This July, Rebecca and I took part in Game Maker’s Toolkit Game Jam 2022 (an annual game jam hosted by the creator of YouTube channel Game Maker’s Toolkit, Mark Brown), making a game called Dice Tower in only fifty hours. It was our first game jam in a long time, having spent the last three years focusing (and failing) on making our “first big release”. Those fifty hours proved to be an intense, fulfilling experience, and I want to examine how things went. I’ll start with the goals that Rebecca and I made, continue into what happened during the jam, and conclude with whether I felt our goals were met and what we’ll do in the future.

Our Goals

First and foremost, Rebecca and I wanted to actually release the game! Our last jam effort, Rabbit Trails, never saw the light of day because we didn’t get the build submitted in time, and we were determined to avoid making that mistake again.

I wrote briefly about this experience as part of my retrospective on 2019.

To that end, we explicitly wanted to scope our game small enough that it had a realistic chance of being completed by jam’s end. Further supporting that goal, we also decided that we would avoid trying to come up with something “clever”; we would be fine with coming up with feasible and fun ideas, even if they might be ideas that other people were likely to come up with. Finally, we determined that we would specifically make a 2D side-scrolling platformer, because that was the genre we were most familiar with; we didn’t want to waste time figuring out how to do a genre that we lacked experience in making.

Based on what had happened in previous jams, we had a few other goals we wanted to meet. Given that our previous games felt bland, we wanted to make sure whatever we made felt more polished and juicy, thereby increasing how good it felt to play. Previous jams had left us feeling burnt out and exhausted, and, while that is a traditional hallmark of game jams, we strongly wanted to avoid feeling that way at this jam’s end, so we made plans to limit how many hours we’d work per day so that we’d have time to relax and get our normal amount of sleep.

Separate from the in-jam goals, we had one ulterior objective: we wanted to see if the idea we came up with was good enough to develop further into a small release. The game we’d been working on, code-named “Squirrel Project”, was still very much in the early prototyping stage; we’d built and tried a lot of things, but made little progress in actually putting together a full game experience. Both of us felt concerned with how much time we were taking in making a “small game”, so we were interested in seeing if doing game jams might give us smaller concepts that would be easier to develop and release quickly. This jam would serve as a proof of concept for this theory.

Day One (Friday, 7/15/22)

The day of the jam arrived. Our son was off spending the weekend with relatives, we’d prepared our meal plan for the next couple of days, and I’d taken time off from my day job. We sat around my laptop, awaiting Mark Brown’s announcement of the theme. At noon, the video was released, and we saw the theme emblazoned on the screen:

Roll of the Dice

Initial Planning

I hated the theme at first impression. One of my takeaways from working on Sanity Wars Reimagined (our first-ever full release) was that working with randomness in game design was hard, and now we had a game theme which strongly implied designing a game focusing around randomness. In my mind, it would be harder to design a game around dice that wasn’t random in some way. Concerned now with whether we would have enough time to make a good game, I started brainstorming ideas with Rebecca.

We spent that first hour working out an idea; the first idea we hit upon wound up dominating the rest of our brainstorming session, to the point that we didn’t seriously entertain anything else. The game would be a rogue-lite platformer, where you moved to various stations and rolled dice to determine which ability you got to use for the next section of gameplay. Throughout the level would be enemies that you could defeat to collect more dice, which would then give you a better chance to roll higher at the ability checkpoints, thereby increasing your odds of getting the “good” abilities.

I intentionally wanted to minimize the randomness of our game so that players felt they had some level of control over the outcomes of dice rolls, and I liked the idea of using dice quantity to achieve this outcome. The more dice you add to a roll, the more likely you are to get certain number totals. This is known as a probability distribution.

At the end of that hour, we formally determined that this was the idea we wanted to work with. Rebecca started crunching out pixel art, and I got to work making a prototype for our envisioned mechanics.

That Old, Familiar Foe

The next few hours of my life were spent working on the various elements that would serve as a foundation for our mechanics. I threw together some simple dice code, along with dice containers that could roll all the dice they were given. I also pilfered my player character and enemy AI code from Squirrel Project, to jumpstart development in those areas.

But something happened as I started trying to work out how I was going to make the player’s abilities work: my brain began to freeze up. This was a frighteningly familiar sensation: I’d felt this way near the end of developing the original Sanity Wars (for Ludum Dare 43). Dark thoughts started clouding my mind:

There’s not enough time to make this game.

You’re going to fail to finish it, just like your last game jam.

Is what you’re feeling proof that you’re not really good enough to be a game developer?

Slowly, I forced myself to work through this debilitating state of mind. After several more hours, I came up with a janky prototype for firing projectiles, and a broken prototype for imparting status effects on the player (like a shield). It occurred to me that if I was having this much trouble making something as simple (cough cough) as player abilities, then how was I going to have time to fix my glitchy enemy AI, and develop the core mechanic of rolling dice to gain one of multiple abilities, and make enough content to make this game feel adequate, let alone good. Oh, and then there was still bugfixing, sound and music creation, playtesting…

It finally hit me: This idea wasn’t going to work. There was simply too much complexity that was not yet done, and I was struggling with the foundational aspects that needed to be built just to try out our idea. There was no way I would be able to finish this vision of our game on time.

My mind in shambles and my body exhausted, I shared my feelings and concerns with Rebecca, and she agreed that we needed to pivot to a new idea. We tried to come up with something, but we were both too tired to think clearly. Therefore, we decided to be done for the evening, get some supper, and head to bed.

Note the lack of planned relaxation time.

As I lay in bed, I fretted about whether we could actually come up with a new idea. That first idea was by far the best of what few ideas we’d been able to come up with during our brainstorming session; how were we going to suddenly come up with an idea that was good enough and simpler? With these worries exhausting my mind, I fell asleep.

This is the first thing I made, a simple test with a dice container and N number of dice. It felt oddly satisfying to keep pressing the “Roll Dice” button.

Day Two (Saturday, 7/16/22)

The next morning, at 6am, I woke up, took a shower, and played a video game briefly. This was my normal morning routine during the workday, and I was determined to keep to it. At 7am, I grabbed a cup of coffee and sprawled out on the couch, pad of paper and pen resting upon an adjacent TV tray, prepared to try and come up with a new idea.

Rebecca joined me at 7:30am, after she did her own waking routines.

The New Idea

I wrote down the elements we already had: Rebecca’s character art and tileset from her previous day’s work, some dice and dice containers, and a player entity that was decently functional as a platformer character. If our new idea could incorporate those elements, then at least not all of yesterday’s work would go to waste.

After thinking about it for a long while, I hit upon an idea: what if you rolled dice to determine how much time you had to complete a level? As you moved through each level, you could collect dice and spend them at the end-of-level checkpoints to increase your odds of getting more time to complete the next level. If that were combined with a scoring system involving finding treasure collectibles that were also scattered throughout each level, then there’d be potentially interesting gameplay around gambling how many dice you’d need to collect to guarantee that you had enough time in each level to collect enough treasure to get a high score.

I pitched the idea to Rebecca, and after some discussion about that and a few other ideas, we decided this was the simplest idea, and therefore had the best chance of being completed before the deadline. Fortunately, this idea also did successfully incorporate most of the elements that we’d worked on yesterday, so we didn’t have to waste time recreating assets. On the other hand, this idea needed to work; there was likely not going to be any time to come up with another plan if we spent time on this one and it failed.

Our idea and stakes in mind, Rebecca and I once more commenced our work.

Slogging Through the Day

I created various test scenes in Godot. Slowly, I began to amass the individual systems and entities that I’d eventually put together to form the gameplay. Throughout the day, I felt very sluggish and lethargic mentally; this was likely a side effect of the burnout I’d put myself through yesterday. I kept reminding myself that some amount of progress was better than none at all, but it still didn’t feel great.

By the start of that evening, I had a bunch of systems, but nothing that fully integrated them. Taking a break, I went outside for a walk and some breaths of fresh air. As I trod the trails in our neighborhood, I worked out the game’s next steps. I reasoned that if I continued to put each system and entity together in isolation and test them, I stood a realistic chance of running out of time to put everything together into a cohesive game. Therefore, I decided to forgo this approach, and simply put everything together now, and build the remaining systems as I went along. This flew in the face of how I traditionally prefer to program things, but I resolved to set aside my clean code concerns and focus simply on getting the game working.

This might look like a game level, but it was really just a single test scene that I was throwing my creations into. There was no logic connecting any of these things together to form a gameplay loop.

The Late Evening Dash

Not long after I returned from my walk, it became 7pm. This was the twelve-hour mark, and in our pre-jam plans I’d determined that I wouldn’t work more than twelve hours on Saturday. Yet I still didn’t have much that was actually put together. I was now faced with a conundrum: should I commit to stopping work now, and risk not having enough time tomorrow to finish the minimum viable product?

Ultimately, I decided that I would try to get an MVP done tonight, or at least keep working until I felt ready to stop. Three hours later, while that MVP was still incomplete, I had put together the vast majority of what was needed to make the game playable: a level loading system, the dice-rolling checkpoints, dice collection (though said dice weren’t yet connected to the checkpoints), the level timer and having it set from rolling the checkpoint dice, rudimentary menu UI, and player death. At this point, I felt that continuing to work would just cut into my sleeping time, and I was still determined to get a proper amount of sleep. At the least, those few hours had produced enough progress that I felt confident that I could finish things up tomorrow morning.

I quickly prepared for bed, and after watching some YouTube to wind down I fell asleep.

One of three tutorial levels I’d created that night. This one is to teach the player that they can pick up dice; when they advance to the next checkpoint, they’ll see that newly-collected die in their dice pool, and hopefully make the connection between the two actions without having to explicitly spell it out.

Day Three (Sunday, 7/17/22)

That morning, I woke up at 6am, as usual, but this time I skipped all of my morning routine save the shower. By 6:30am, I was at my computer and raring to go.

Blazing Speed and Fury

The first thing I did was export the game as it currently was. I’d been burned enough times by last-minute exports that I was determined to make sure that didn’t bite me in the butt this time. Fortunately, this time there were no export-specific crashes or bugs, so I resumed work on the game proper.

For the next several hours, my mind singularly focused on getting this game done. I finally made the checkpoints accept the dice you collected, thus completing the core loop of rolling dice to determine the time you had to make it through the level. I added game restart logic, added transition logic for when the player was moving between levels, added endgame conditions and win/loss logic, and fix various bugs encountered along the way. I also realized that I wouldn’t have time to implement a scoring system, so I unceremoniously cut it from the MVP features.

Cutting the scoring system also meant cutting the third tutorial level, which would have taught the player about the treasure collectible. Additionally, it would’ve served as a prelude to the intended tension of collecting treasure to increase your score and collecting enough dice to have more time in the next level.

Around noon, I finally had the game fully working. I could boot the application, start a new game from the main menu, play through all the designated levels, and successfully reach the victory level to win the game (or run out of time and lose). If nothing else, we at least had a playable game!

Final Push

The game jam started at noon on Friday, and as it was now noon on Sunday that meant 48 hours had passed. Thankfully, the jam had a two-hour grace period for uploading and submitting games to Itch.io. That meant I had less than two hours to jam as much content and polish into the game as I could before release!

I blazed my way through creating six levels, spending less than an hour to do so. Of course, that meant I had little time to balance the levels properly, beyond ensuring they could be completed in an average amount of time. One thing I did spend time on was adding the various pieces of decorative art Rebecca made to each level. It might seem frivolous to add decorations, but I think having a nicely-decorated level goes a long way towards breaking up level monotony and sameness, and honestly it didn’t take that long for me to add those things.

After a few trials, I hit upon a solution for balancing the randomness for the dice checkpoints: I’d give the player six free seconds at the start of each level, and a single die at each checkpoint (in addition to the ones collected through gameplay). As I playtested the level, that at least felt long enough that, using probability curves, the average player could have a decent chance of finishing each level.

Intentionally, I chose to not focus at all on adding sound effects and music. My reasoning went thusly: players would probably prefer to have more content to play through than have sound and music with very little content. It made me remorseful, because sound can make an okay game feel great, but there just wasn’t enough time to do a good job of it, so I decided it was better to just cut audio entirely.

Finally, at 1:30pm, I looked at what we had and determined it was good enough. Rebecca had been working on setting up our Itch.io page, and I gave her the final game build export to upload to the store page. We submitted the game just in the nick of time; shortly after our submission was processed, Itch.io crashed under the weight of thousands of last-minute uploads. While this server strain prevented us from adding images for our game page (we got them in later), at least we already had the game uploaded and submitted, so we weren’t in danger of missing the deadline.

Rebecca and I looked at each other. We’d done it! We’d successfully made a game and submitted it! We spent the rest of the afternoon out and about on a date, taking advantage of our last bits of free time before returning to parenthood the next day.

Feedback

Over the next week, our game was played and rated by people. We received multiple comments about how people enjoyed the core idea, which was encouraging.

A couple of our friends from the IGDA Twin Cities community took it upon themselves to speedrun our game. This surprised me, because I thought the inherently random nature of our game would be a discouragement from speedrunning. They told me they enjoyed it a lot, however, and over the course of that week they posted videos of ridiculously speedy runs and provided good feedback.

By happenstance, the Twin Cities Playtest session for July was that same week, so Rebecca and I submitted Dice Tower to be played as part of that stream. Mark LaCroix, Lane Davis, and Patrick Yang all enjoyed the game’s core concept, and gave us tremendous feedback on where they felt improvements could be made, as well as different directions we could go to further expand and elaborate on the core mechanic. It was a great session, and we are greatly indebted to them for their awesome feedback.

After the play-and-review week had passed, Mark Brown made his video announcing the winners of the jam, and we got to see our final results online (we did not make it into the video, which only featured the top one-hundred games).

For a game jam with over six thousand entries, we did surprisingly well, placing in the top 50% in overall score. Our creativity score was in the top third, which pleased me greatly; it felt like further validation that our core concept was good enough to build on.

Reflection

I want to circle back to those goals Rebecca and I set before the jam, and see how we did in meeting them. There were a couple of other takeaways I had as well, which I’ll present after looking at the goals.

Did We Meet Our Goals?

First and foremost, we wanted to release a game, and we did! That was huge for us, given our last effort died in development. In particular, to release this game after the mental fracturing I endured on Friday night, and having to pivot to a new idea, shows that, perhaps, we’re decent game developers, after all.

Did we scope our game properly? At the beginning, no, definitely not. Fortunately, we recognized this (albeit after spending a day on it), and decided to change to a more feasible idea. Even though we had to cut scope from the new idea as well, the core was small enough that we were able to make it in the time allotted. It gives us a new baseline for how much work we can fit in a given amount of time, which should serve us well in future endeavors.

It’s a similar story for our theme interpretation. Our first idea seemed simple, but turned out to be complex under the hood, as it’s a lot of work to not only add lots of different player abilities, but game entities (such as enemies) to use those abilities on. In hindsight, I laugh at how we thought that kind of game was feasible in 48 hours, with not nearly enough foundation in place beforehand. That said, once again, we pivoted from the complex to the simple, and the new theme interpretation was simple enough to be doable.

Ironically, I thought this would be a common enough idea that plenty of other people would do it, but I actually never encountered a mechanic similar to this during my plays of other jam games, and multiple people commented on the novelty of the idea. Perhaps our focus on coming up with a good idea instead of a unique one managed to get us the best of both worlds!

We stuck to our guns and made a 2D side-scrolling platformer, even though at times I felt like that made it more difficult to find a good theme interpretation. Because we knew how to work in that genre, it made our mid-development pivot possible; I don’t think we could have been successful in doing that if we’d tried to make something unfamiliar to us. Additionally, I think using a genre where dice are less commonly used led to coming up with something more unique than we might’ve if we’d done an RPG or top-down game (two genres I thought would be easier fits for the theme).

One area we did miss on was making this a polished release. The missing audio was sorely felt. That said, I really like the art that Rebecca came up with, especially the decorations, and I don’t regret the decision to cut sound in favor of making levels and placing her doodads. Honestly, despite the missing audio, the fact that this game was fun and playable made this jam release feel more polished than our previous jam efforts.

That dice banner and the dice family portraits were particularly fun to place throughout the levels.

A big success we had was in self-care management. Even though we didn’t stick to the maximum hours per day we set before the jam, we took care to make sure we got enough sleep each night. The end result is that this is the first jam we’ve done that both of us didn’t feel utterly spent at the end of it. That allowed us to enjoy a lovely afternoon and evening together as a couple, and we didn’t feel totally shot for days thereafter. I think that also helped us have the energy needed to push us through to the finish line.

One final goal remains to be evaluated: was our game good enough to base a future release upon? The answer is “yes”. Based on the enthusiastic feedback we received, plus our own thoughts about where the concept could go, we’ve decided to put Squirrel Project aside and focus on making a full, but small, release out of Dice Tower. With some more features and polish, and maybe a dollop of background story to tie things together, we think Dice Tower could make a good starting point for our first paid release.

Additionally, we plan to take part in future game jams, and further explore the concept of making quick games to find small ideas with good potential.

Other Takeaways

There were some additional things we learned from the jam. These emerged as byproducts of the things we tried during the jam.

Our initial thoughts were that we’d spend our brainstorming session coming up with multiple ideas, and then make small prototypes for each of them and decide which of them was the one we wanted to make. It didn’t turn out that way; both our first and second attempts settled early on a single idea, to the point where we didn’t really have many other ideas that we seriously considered. I think that perhaps that’s just how Rebecca and I work; it’s easier for us to jump into an idea and try it rather than piece a bunch of ideas together and flesh all of them out on paper. Perhaps in our next jam, then, we’ll deliberately settle on an idea right away and just go for it, making explicit allowance for pivoting if it starts feeling like too big an idea to work with.

Personally, I also learned that I need to let go of trying to test every little thing in isolation. That may be a good approach for building long-lived, stable systems, but for something as volatile as game prototyping it just slows the process down too much, with no game to show for it. By putting things together as early as possible, it makes things feel more real because it is the real game! I’ll keep this in mind for future projects, to just make a go of it right off the bat, and save my efforts to make things nice and tidy for when the ideas are codified and made official.

Conclusion

Ultimately, I’m glad Rebecca and I decided to participate in GMTK Game Jam 2022. It feels exhilarating to not only finish a game in that short amount of time, but to defeat some of my internal demons from previous jams in the process. We feel more confident in our ability to develop and release games, and we’re excited to tackle making the full release of Dice Tower.

It’ll be interesting to compare this postmortem with the postmortem for whatever that game becomes!

In the meantime, though, feel free to try out our jam release of Dice Tower and let us know what you think!

Sanity Wars Reimagined released!

The game PixelLunatic and I have been working on for the past seven months, Sanity Wars Reimagined, has been officially released! Download it here.

It’s been a long seven months, working on this game, and while there’s still plenty of things that could be improved, overall I’m pleased with how this game turned out. Most importantly, we learned many things that will prove useful for our future game development endeavors.

We hope you enjoy our game!

Examining the EMMI Zones of Metroid Dread

I’ve been playing Metroid Dread recently (with one finished playthrough under my belt). It’s the first Metroid game I’ve played (though I’ve played other Metroidvanias), and I absolutely enjoyed it. There are many mechanics that I found fun: the combat is simple, yet engaging; the various abilities you unlock are interesting and lead to great gameplay moments; the level design both helps you avoid getting too lost and still lets you feel like you can explore and discover new areas; and the boss battles are tough, yet fair.

The flagship mechanic, the one that Nintendo advertised heavily, are the EMMI zones. These are designated sections of a map patrolled by a powerful EMMI robot, whose sole purpose is to hunt you down. Your normal weapons can’t hurt the EMMI, so you have to avoid encountering them while moving through their territory. If an EMMI catches you, it kills you unless you succeed on a low-probability counter move. There’s only one way to stop an EMMI for good: finding the energy to power your Omega Cannon, the one weapon you have that can damage them.

EMMI Zones present an action-oriented take on stealth gameplay, and I think they pull the job off well. They’re designed to give you a challenge that you can’t blast your way through, and are crafted such that they don’t put you through too much of their gameplay. In this blog post, I want to examine EMMI zones in two ways: how the game teaches you about the zones, and what mechanics are used to make the zones work.

Note: There will be discussion of some of the abilities you earn throughout the game, though there won’t be any spoilers about the game’s story.

How the Game Teaches You About EMMI Zones

Looking at EMMI zones as a whole, there’s a lot to consider, and it can be a little complex. Metroid Dread spends a good deal of time in the early parts of the game guiding you through the gameplay, using a combination of in-game cutscenes, scripted gameplay, and overt tutorialization. Through these approaches, the game allows you to get used to how EMMI zones work, while still having fun along the way.

The First EMMI Zone

When you first encounter an EMMI, you are shown a cutscene, after which you are given a moment to try and respond to it with what limited abilities you have. The door behind you doesn’t open, and your normal beam weapon and missiles cause no damage to the robot. You are powerless to stop the EMMI from capturing you. At the moment of capture, however, the game pauses, explaining that you have a chance to try and parry the EMMI before it lands a killing blow, and waits to resume until you press the melee counter button. The EMMI freezes in response to this parry, and you are told that you can slide beneath a stunned EMMI. This sequence teaches you what happens when an EMMI catches you, and that you are not powerless to respond to it.

The EMMI recovers from the stun, and you are left to figure out how to run from it. In the next room, the level is designed with a tall wall and platform that you can bounce up and escape. The EMMI is damaged, so even though it tries to follow you, it cannot. The fact that it tries, however, suggests that this is what the other EMMI robots will try to do.

In the very next room is the Omega Cannon, the weapon you need to destroy the EMMI. First, you get a tutorial that teaches you how the Omega Cannon’s charge blast works, by forcing you to use it to open an exit out of the room. Afterwards, you drop back down to face the EMMI, and you have to use the cannon to destroy it and continue on your way.

The Second EMMI Zone

The next EMMI zone is right next to the first one, so you get a chance to try a less hand-held version of EMMI zone gameplay. It starts with a cutscene that reinforces the fact that your normal weapons don’t work against the EMMI (in case you hadn’t realized that, yet). You then have to escape from the EMMI; however, unlike the first one, this EMMI isn’t damaged, so simply climbing up a wall is not enough. You have to evade the EMMI through multiple rooms long until it loses sight of you. This causes it to leave pursuit mode, allowing the EMMI zone doors to unlock and giving you the chance to get out.

From that point, the game leaves you alone, letting you explore more of the world, discovering some new powers and augmentations along the way. The level design forces you to cross back through the EMMI zone multiple times to get to the places you need to go, giving you plenty of experience avoiding the EMMI.

Eventually, you encounter the first Central Unit room, the place where an entity coursing with Omega Energy (the resource that powers your Omega Cannon) is housed. You have to battle this Central Unit, dodging two attacks while blasting the Central Unit with missiles to take down its armored shell and squishy body. Finally, the entity dies, allowing you to siphon its Omega Energy to power the cannon. This time, you are given a second facet to the Omega Cannon: a rapid-fire blast.

As with the first room, the game locks you into the Central Unit’s room and forces you to use your Omega Cannon’s abilities to break out of it. You have to use the rapid-fire to melt the exit door’s heat shield, exposing it to a charge blast which blows it open. This same combination is what you use to defeat the EMMI. This time, when the EMMI dies, you acquire an ability from it, hinting that future EMMI will do the same.

The last major aspect of EMMI zone gameplay comes after you defeat the game’s first boss, where you acquire the Phantom Cloak ability. This turns you invisible for a short period of time. A short briefing explains how the Phantom Cloak can be used to hide yourself from EMMI detection, which is reinforced by a short cutscene when you enter the next EMMI zone, where Samus goes undetected by the next EMMI when she employs the Phantom Cloak.

At this point, you’ve been given the abilities you need to handle any challenge the EMMI zones can throw at you. Along the way, the game gave you a tour of how gameplay within EMMI zones will work, both teaching you through tutorial and allowing you to experiment and try things for yourself.

How do those abilities come together with the rest of the game design to give great gameplay? That’s what I want to examine next.

The Design of EMMI Zone Gameplay

The bulk of gameplay in Metroid Dread consists of exploration, small enemy encounters, and boss fights. Lots of action, lots of things to discover, lots of abilities to unlock progression to other parts of the world. Compared to this run-and-gun style of gameplay, EMMI zones feel tense. You can’t blast your way out of the problem; you have to plan your next moves carefully, with the occasional rapid, improvised escape. This is a good change-up in gameplay, giving you a different style of experience; at the same time, it doesn’t last too long, so you don’t spend too much time under tension, helping you avoid becoming fatigued.

Let’s take a look at the various components which power this experience: level design, evasion, and encounters.

Level Design

There is plenty of great map design in Metroid Dread. Seemingly impossible paths are unlocked by new abilities you discover, clever use of one-way gating keeps you from getting too lost, and many skillful sections conceal power-ups to reward conquering the challenge.

Likewise, the EMMI zones are carefully designed, not just in and of themselves, but also with respect to supplementing the rest of the map design. Each zone is placed on the map such that you are forced to cross through multiple times to accomplish your other goals. At the same time, the EMMI zones are only one part of a larger world, so you aren’t constantly forced to stay long in these high-tension areas. It helps keep the gameplay novel and interesting, without putting too much emphasis on having to play stealthy.

How about the level design within each EMMI zone? By and large, there are two kinds of map design within EMMI zones: large, open spaces where you get plenty of space to move around, and small, narrow corridors that require specific strategies to traverse through safely. While there are rooms within the EMMI zones which are one or the other of those types, often you’ll encounter rooms which mix both types of design together, providing variety in how you plan and execute your evasion. There are also some special areas to help or hinder your approach, including spider magnet walls and ceilings to cling to, pressure plate doors requiring fast maneuvering to blast through, and waterlogged floors that inhibit your movement.

An important aspect of the level design is that it gives you ways to evade the EMMI. When an EMMI has detected your sound, it will pursue your sounds until it finds you or you get far enough away that it stops investigating. The level design supports many strategies for getting out of this pursuit. For instance, you can lead the EMMI off into an isolated part of the map, then double back down a different path to go around it to try and quickly reach your objective. Another way is to take advantage of your mobility to get to areas of the map the EMMI can’t immediately follow you to, forcing it to take another path to get there and increasing the time you have to get out of pursuit range entirely. You just have to look at the map and figure out how best to make your way through safely.

Finally, the visual look of the levels themselves contribute to how the player should feel inside an EMMI zone. While the EMMI is still alive and patrolling, the entire area is grainy and gray, and haunting tones play in the background. Once the EMMI is defeated, the entire area brightens up, the grainy filter is gone, and you hear no more spooky music. Additionally, the world map changes the EMMI zone area to have green backgrounds, indicating you’ve cleared that zone.

Evasion

You can’t hurt the EMMI without the Omega Cannon, and the level design forces you to move in and out of EMMI zones several times before you gain access to the room housing the energy which powers that cannon. That leaves you with two options for dealing with the EMMI while on their turf: running and hiding.

Running is the most obvious solution, and there are various ways the game encourages you to do so and not move too slowly. Your Aeion energy, the ability which powers your Phantom Cloak (and certain other moves) recharges more quickly when you move, so you have to move around at some point to regain your ability to hide. A lot of the map design encourages hiding in a safe spot to plot your next move, then darting over to the next safe spot to repeat the process all over again. The more quickly and carelessly you move, however, the more “noise” Samus makes, increasing the odds that the EMMI will hear you and come to investigate your position. You can risk running for an exit, but if you’re spotted, the EMMI zone exits close until you break the pursuit.

The Phantom Cloak, once you’ve acquired it, allows you to find a spot safe from EMMI wandering and hide from visual detection. While active, it drains your Aeion energy resource, but standing still makes the resource drain significantly less than if you are moving while cloaked. This, along with Aeion energy recharging faster when you move (if you aren’t using an Aeion ability) encourages you to plan your next moves while cloaked, uncloak to execute that plan, then activate the cloak again in your next safe spot to make the next step of your plan. Of course, things don’t always work the way you planned them, and a quick activation of the Phantom Cloak gives you a quick way out of being spotted, hopefully allowing you time to get away from the EMMI threat.

Another aspect of Phantom Cloak is that the game allows it to drain life energy if you run out of Aeion energy while cloaked, and this functions as a risky way to prolong your hidden state. It makes for an interesting player decision: do you continue using the Phantom Cloak and risk losing too much life to deal with enemies beyond the EMMI zone, or do you uncloak and risk the threat of EMMI detection? It presents yet another interesting facet to EMMI zone gameplay.

All the decisions you need to make while in the EMMI zone are aided by the information the game chooses to give you while in the zone. If the EMMI is outside of the screen, but close to you to be within the minimap, a red dot appears on the minimap to indicate its whereabouts. Once an EMMI gets close enough to detect the noises you make, a big yellow circle appears on screen to illuminate the precise area within which it can hear you, and while in this area your sound-making movements are highlighted by smaller yellow circles, letting you know exactly what you’re doing to attract the EMMI’s attention. A blue cone is projected from the EMMI’s face, representing the area in which the EMMI can see you, allowing you to react to its sight and do your best to stay out of it. Finally, if it sees you, the cone turns red during the short moment of time the EMMI spends transitioning to pursuit mode, giving you an opportunity to get a head start on your escape.

Engaging the EMMI

Much of the time you spend in an EMMI zone revolves around avoiding EMMI interaction, because to do so risks death. You can’t run from them forever, though. Let’s take a look at the two ways you can directly interact with the EMMI: attacking it with the Omega Cannon, and attempting to escape its grasp when you are caught.

The Omega Cannon has two forms: one gives you a rapid-fire stream of energy bullets, or the Omega Stream, the other a blast with a charging period, or the Omega Blaster. You need both abilities (after the tutorial zone) to defeat an EMMI: Omega Stream is required to take down the shielding on the EMMI’s head, and Omega Blast is needed to take out the core once the shielding is down.

It takes a lot of rapid-fire shots to take the shielding down, so you’ll need to maneuver through the environment to find long stretches of corridor to give you enough time to land enough shots to take down the shield. Oftentimes, the corridor you’re in isn’t quite long enough to completely destroy the shield, so you have to judge when to disengage and move away to avoid getting caught, and subsequently where you’ll move to next to renew the assault. The shield also regenerates if you haven’t taken it down and you stop damaging it, so it’s not as simple as firing a few shots, moving away, and firing a few more shots; you inherently have to take some risky positioning to make sure you do enough damage in one encounter to not allow the shielding to fully recharge by the next time you position yourself to strike.

Once the shield is taken down, the EMMI is stunned for a brief period of time. If you’re not too close, you can start charging your Omega Blaster during this period. Otherwise, you once again need to move far enough away that you give yourself enough time to charge up the blast and aim for the head. This can lead to some tense, thrilling moments where you hold your ground and manage to get your shot off just before the EMMI catches you.

(Yeah. That was close.)

Something you’ll need to adapt to is the varying speeds EMMI will use when approaching you. Sometimes, they’ll come at you slowly, giving you plenty of time to damage them; other times, they’ll come at you rapidly, and you may find yourself needing to risk your position to get a few more hits in before you move away. The more you engage with an EMMI, the more of a feel you’ll get for the speeds it’ll employ and when it’ll employ them, giving you more information to use in planning your attack.

What if you are caught? When the game launches you into an EMMI capture sequence, you are given two chances to counter the EMMI’s capture strike: once when it grabs at you, and once more when it goes for the killing blow. In both cases, the timing of when the move happens is randomized, so you essentially have to guess when it’s going to come and hope you guessed correctly. You are told that it is almost impossible to counter these blows, which makes it all the more thrilling when you do succeed in landing the parry and are able to escape the EMMI’s clutches. Most of the time, the counter will fail, but by giving you a slim chance of escape, despite failing most of the time you will still feel as though you had some measure of control over your fate.

As someone who specifically dislikes gameplay where failing at stealth immediately results in total failure, I really appreciated this approach to giving you a chance to get out of trouble, even though most of the time I failed to do so.

Even when the EMMI lands the killing blow and you have to reload, the game spawns you just outside of whichever EMMI zone entrance you came through, instead of forcing you to start from wherever you last saved. This allows you to immediately go back in and try again without having to fight your way back; alternatively, if you want to take a break from EMMI zone gameplay, you can wander off and do something else for awhile before diving back in. This is a great approach to minimize player frustration with failure, by making the consequence of it less severe.

There is also something to be said to having an enemy that constant hunts for you, that you can do nothing about but to evade. The feeling you get when your efforts finally lead to you gaining the power to destroy that hunter once and for all is exhilarating, leaving you fired up and raring to take on the next EMMI.

As shown, there are many different mechanics that come together to make up the EMMI zone experience. From the level design, to the various ways you are given to evade the EMMI, to how you engage the EMMI directly, these mechanics come together to provide plenty of experiences for you within an EMMI zone.

Conclusion

Metroid Dread is an awesome game, in my opinion, and a large contributor to that great gameplay are the EMMI zones. You are taught how handle EMMI zones through a combination of guided experiences, cutscenes, and gameplay. Afterwards, the various game mechanics specific to EMMI zones come together to form a tense, challenging experience that straddles the line between being fun and frustrating.

I think the game would be more boring without EMMI zones, and that is a testament to how effectively they are designed. If ever I want to implement action-based stealth mechanics into my own games, I’ll be taking cues from Metroid Dread’s EMMI zones as an example of how to do it right.

Creating a Debugging Interface in Godot (Part 1)

At some point during the development of a game, you need to be able to show information that helps you debug issues in your game. What kind of information? That really depends on your game and what your needs are. It could be as simple as printing some text that shows the result of an internal calculation, or it could be as fancy as a chart showing the ratio of decisions being made by the game’s artificial intelligence.

There are different kinds of debugging needed as well. Sometimes, you need something temporary to help you figure out why that function you just wrote isn’t behaving the way you expect it to. Other times, you want an “official” debugging instrument that lives on as a permanent display in your game’s debugging interface.

How does one go about building a debugging system, however? In this blog tutorial, we’ll build a debugging system in the Godot game engine, one that is flexible, yet powerful. It’s useful both for temporary debugging and a long-term debugging solution. I use this system to provide a debugging interface for my own games, and I want to share how to make one like it in the hopes that it helps you in your own game development efforts.

This will be a multiple-part series. At the end of it, you’ll have the root implementation of the debugging system, and knowledge on how to extend it to suit your debugging purposes.

If you want to see the end result, you can download the sample project from Github: https://github.com/Jantho1990/Sample-Project-Debug-Interface

Existing Debugging Tools in Godot

Godot comes with a number of functionalities that are useful for debugging. The most obvious of these is the trusty print() function. Feed it a string, and that string will get printed out to the debugging console during game runtime. Even when you have a debugging system in place, print() is still useful as part of your toolset for temporary debugging solutions. That said, nothing you show with print() is exposed to an in-game interface, so it’s not very useful if you want to show debugging information on a more permanent basis. Also, if you need to see information that updates on every frame step, the debugging console will quickly be overwhelmed with a flood of printed messages, to the point where Godot will bark at you about printing too many messages. Thus, while print() definitely has its uses, we are still in need of something more robust for long-term debugging solutions.

One way I solved this problem in the past is by creating a DebugLabel node, based on a simple Label. This node would listen for a signal, and when said signal was received it would set its text value to whatever string was sent to it. The code looked something like this:


# DebugLabel
extends Label
export(String) var debug_name = "DebugLabel1"

func _ready() -> void:
  GlobalMessenger.listen(debug_name, self, "on_Debug_message_received")

func _on_Debug_message_received(data):
  text = str(data)

This solution also depended on a separate GlobalMessenger system that functions as a global way of passing information. But that system is a tale for another day.

This gave me a solution for printing debugging information that updated on every process step, without overloading the debugging console. While this little component was useful, it had its drawbacks. Every call to print a message to the DebugLabel would overwrite the previous value, so if I needed to show more than one piece of updating information, I would have to create multiple DebugLabel nodes. It wouldn’t take long for my scenes to be cluttered with DebugLabel nodes. Also, this still wasn’t part of a debugging system. If there was a DebugLabel, it’d show, regardless of whether you needed to view debugging information or not. Thus, while this node also served a valuable purpose, it was not enough for a proper debugging solution.

So what does a debugging solution need? It needs a way to conditionally show and hide debugging information, depending on whether such information needs to be viewed. It also needs to expose a method for game code to interact with it to pass in debugging information. There are many possible kinds of information that we’d want to see, so this interaction method must support being able to accept multiple kinds of information. Finally, there should be an easy way of creating debugging scenes to organize the information in whatever ways make sense to those that view the debugging information.

With that high-level information, let’s start by tackling the first part of that paragraph: conditionally showing and hiding the debugging information.

Creating a Test Scene

But before we start working on the debugging system proper, we should have a test scene that exists to help us test that what we’re creating actually works. It doesn’t need to be anything fancy.

While this part of the tutorial is optional, the tutorial series will be assuming the existence of this test scene. If you choose not to make it, then you’ll have to figure out how to test the debugging system’s code in a different way.

Create a scene, and have it extend Node. Let’s call it “TestScene”. In TestScene, add a Line2D node, make it whatever color you want (I chose red), and set the points to make it some easily-visible size (I set mine to [-25, 0], [25, 0] to make a 50px-long horizontal line). Move the Line2D somewhere near the center of the scene; it doesn’t have to be exact, as long as it isn’t too close to the top or edge of the game window. Finally, click the triangle button to run Godot’s main scene; since we don’t have one defined, Godot will pop up an interface that will allow you to make TestScene the default scene, which you should do.

You can alternatively just run this individual scene without making it the main scene; I have chosen to make it the main scene in this tutorial purely out of convenience.

This is what my version of the test scene looks like after doing these things:

Now that we have a test scene, let’s get to building the debugging system proper.

Creating the DebugLayer Global

We need a way to interact with the debugging interface from anywhere in our game code. The most effective way to do this is to create a global scene that it loaded as part of the AutoLoads. This way, any time our game or a scene in our game is run, the debugging system will always be available.

Start by creating a new scene, called DebugLayer, and have it extend the CanvasLayer node. Once the scene is created, go to the CanvasLayer node properties and set the layer property to 128.

That layer property tells Godot what order it should render CanvasLayer nodes in. The highest value allowed for that property is 128, and since we want debugging information to be rendered atop all other information, that’s what we’ll set our DebugLayer to.

For more information on how CanvasLayer works, you can read this documentation page.

Now, create a script for our node, DebugLayer.gd. For now, we’re not going to add anything to it, we just want the script to be created. Make sure it, as well as the DebugLayer scene, are saved to the directory _debug (which doesn’t exist yet, so you’ll need to create it).

Finally, go to Project -> Project Settings -> AutoLoad, and add the DebugLayer scene (not the DebugLayer.gd script) as an AutoLoad, shortening its name to Debug in the process. This is how we’ll make our debugging interface accessible from all parts of our game.

Yes, you can add scenes to AutoLoad, not just scripts. I actually discovered that thanks to a GDQuest tutorial on their Quest system, and have since used that pattern for a wide variety of purposes, including my debugging system.

To verify that our DebugLayer shows in our game, add a Label child to the DebugLayer scene, then run the game. You should be able to see that Label when you run the game, proving that DebugLayer is being rendered over our TestScene.

Toggle Debug Visibility

This isn’t particularly useful yet, though. We want to control when we show the debugging information. A good way to do this is to designate a key (or combination of keys) that, when pressed, toggles the visibility of DebugLayer and any nodes it contains.

Open up the project settings again, and go to Input Map. In the textbox beside Action:, type “toggle_debug_interface” and press the Add button. Scrolling down to the bottom of the Input Map list will reveal our newly-added action at the bottom.

Now we need to assign some kind of input that will dispatch this toggle_debug_interface action. Clicking the + button will allow you to do this. For this tutorial, I’ve chosen to use Shift + ` as the combination of keys to press (Godot will show ` as QuoteLeft). Once this is done, go ahead and close the project settings window.

It’s time to start adding some code. Let’s go to DebugLayer.gd and add this code:


var show_debug_interface = false


func _ready():
  _set_ui_container_visibility(show_debug_interface)


func _set_ui_container_visibility(boolean):
  visible = boolean

Right away, the editor will show an error on the visible = boolean line. You can confirm the error is valid by running the project and seeing the game crash on that line, with the error The identifier "visible" isn't declared in the current scope. That’s because CanvasLayer doesn’t inherit from the CanvasItem node, so it doesn’t contain a visible property. Therefore, we’ll need to add a node based on Control that acts as a UI container, and it is this node that we’ll toggle visibility for.

CanvasItem is the node all 2D and Control (aka UI) nodes inherit from.

Add a MarginContainer node to DebugLayer, calling it DebugUIContainer. Then, move the test label we created earlier to be a child of the DebugUIContainer. Finally, in DebugLayer.gd, change the visibility target to our new UI container:


onready var _uiContainer = $DebugUIContainer


func _set_ui_container_visibility(boolean):
  _uiContainer.visible = boolean

You may notice that I’m prefixing _uiContainer with an underscore. This is a generally-accepted Godot best practice for identifying class members that are intended to be private, and thus should not be accessed by code outside of that class. I also use camelCase to indicate that this particular variable represents a node. Both are my personal preferences, based on other best practices I’ve observed, and you do not need to adhere to this style of nomenclature for the code to work.

At this point, if you run the test scene, the test label that we’ve added should no longer be visible (because we’ve defaulted visibility to false). That’s only half the battle, of course; we still need to add the actual visibility toggling functionality. Let’s do so now:


func _input(_event):
  if Input.is_action_just_pressed('toggle_debug_interface'):
    show_debug_interface = !show_debug_interface
    _set_ui_container_visibility(show_debug_interface)

_input() is a function Godot runs whenever it detects an input action being dispatched. We’re using it to check if the input action is our toggle_debug_interface action (run in response to our debug key combination we defined earlier). If it is our toggle_debug_interface action, then we invert the value of show_debug_interface and call _set_ui_container_visibility with the new value.

Technically, we could just call the visibility function with the inverted value, but setting a variable exposes to outside code when the debug interface is being shown. While this tutorial is not going to show external code making use of that, it seems a useful enough functionality that we’re going to include it nonetheless.

Run the test scene again, and press Shift + `. This should now reveal our test label within DebugLayer, and prove that we can toggle the debug interface’s visibility. If that’s what happens, congratulations! If not, review the tutorial to try and identify what your implementation did incorrectly.

Congratulations!

We now have the basics of a debugging interface. Namely, we have a DebugLayer scene that will house our debugging information, one that we can make visible or invisible at the press of a couple of keys.

That said, we still don’t have a way of actually adding debugging information. As outlined earlier, we want to be able to implement debugging displays that we can easily reuse, with a simple API for our game code to send debugging information to the debugging system.

To accomplish these objectives, we’ll create something that I call “debug widgets”. How does a debug widget work? Find out in the next part of this tutorial!

You can review the end state of Part 1 in the Github repo by checking out the tutorial-part-1 branch.

Bumbling Dwarves

I discovered Koji recently. Basically, it’s a service where coders create templates of projects, including games, for other people to download and customize in whatever ways the programmer allows them to do. Not only that, but the end user can also access the code for the template and make changes to that as they desire.

Figuring I’d give the service a try, I signed up for an account and spent tonight crafting my first game on the platform, a Match-3 clone based on their starter template called Bumbling Dwarves. You can click the link to play, or play it in the embed below!

Working with Koji was pleasant. Honestly, the majority of the time I spent on this project was restyling the open-source artwork I used for this project, as the original images clashed with each other. I wound up coloring the dwarf sprites to be visually distinct, and I softened the lights on the background image.

Using the template was easy, and it made everything simple to customize, just based on the template alone, and for the few code customizations I made (such as changing the color of the selection box) I had full access to the source code (the template was written in React).

The primary way you interact with the code is through Koji’s online editor, which is based on the Monaco editor (the same one that powers VS Code). They give you two ways to interact with the settings files: a visual editor which functions like a form, and the underlying JSON file that you can change in the editor. When I was finished making my customizations (including custom sounds and music), I filled out their short publication form, hit the publish button, and after a few minutes the project was published on https://withkoji.com/, where their projects are hosted.

I can definitely see how this perpetuates Koji’s mission of making app development and MVP prototyping fast, easy, and accessible even to non-coders. If not for those pesky images, I could easily have deployed Bumbling Dwarves in an hour or two.

This was a fun experience overall, and I’m thinking about messing around with Koji more in the near future. At the very least, I’ll be keeping tabs on this cool, interesting service.

If you want to check out other Koji projects from other users, visit https://withkoji.com/