Friday Fun #13

Welcome to Friday Fun, the blog where I poke my head up from underground, let you all know I’m still alive, and hopefully entertain you with some bits about my project progress and game development experience.

Toward Turing Completeness

One big accomplishment this week in Dehoarder 2 is that now any entity in the game can contain Junk items. This was implemented so that items could be stored in containers and then be retrieved in the same state later (as opposed to Junk Spawners that generated junk from a Loot Table.)

Depending on the application, contained items can be retrieved in last-in-first-out (LIFO) order (stack), first-in-first-out (FIFO) order (queue) or random order. Of particular interest are the LIFO and FIFO retrieval modes. It suddenly occurred to me that such a container of junk with either of those modes can serve as a storage “tape” to drive a computer built from junk within the game! All that should really be needed are items that can serve as NOT and OR logic gates, a way to automatically transfer junk between containers, and a way to keep it all going.

If I can pull this off, Dehoarder 2 would join the elite ranks of games whose mechanics are (effectively) Turing complete such as Minecraft, Factorio, Dwarf Fortress, and Magic the Gathering!

Interactions Overhaul

The real, immediate purpose of all of this container madness was to support the ongoing in-game UI and Interactions overhaul.

The gameplay flows for Gathering are in place and starting to work well. I am now to a point where I can pick up an empty trash bag, which enables a “Dispose” interaction on items that can be thrown in the trash. When enough items have been “Disposed” to fill the bag, Gather mode ends, and the trash bag is replaced with a “Full” version that can be taken to the curb. You can even stop gathering in the middle of filling the bag, which leaves you holding a bag scaled to represent how filled it currently is.

Targeting is now shared among all modes as an overlay (separate from the Reticle overlay mentioned last time), and the item HUD that shows available interactions is also a cross-mode overlay. Defining the available list of interactions at any given point was a good challenge, one that is still not entirely solved. As of now, an item can define a separate list of possible Interactions for each UI mode that shows the item HUD. In addition, an item defines a number of allowed “Override” interactions that correspond to primary Interactions that can be defined on a tool. (A “Primary” interaction is one that is bound to the “Primary” action button, i.e. Action button 1) If the held tool’s primary interaction is in the item’s allowed Override list, then that interaction becomes the Primary interaction for the item, overriding the normal Primary interaction. Simple, right? Here’s an example using the actual Lua definitions for a sample Junk item:

Interactions defined for the Baseball junk object

This is our interaction information for the Baseball junk item. Looking at this, we can see that in both Interact and Gather UI modes, the “PickUp” interaction is available. However, below that we see that with the right tool equipped, the baseball can have the “Dispose” and “Donate” interactions.

A Tool definition for a Trash Bag, showing a Primary Interaction of “Dispose”

This is the definition for one of our Trash Bag tools. Its Primary Interaction is “Dispose”. This means that when the Trash Bag tool is in use, if the targeted item allows “Dispose” as an override, “Dispose” will appear as the primary interaction, overriding the blank slot that would otherwise be there.

The result of combining the baseball’s Interactions for Gather mode with the Trash Bag tool’s Primary Interaction

What remains is to implement the ability to define arbitrary rules that dictate when a defined Interaction should not be available. For example, the house Telephone object has an “Answer” interaction defined. However, this interaction should only be available while the phone is ringing.

Database Decoupled

Keeping a clean coding architecture for any development project, game or otherwise, is an ongoing struggle. It’s not something that you just establish once at the beginning of the project, resulting in magically having clean architecture for the life of the project. It is often impossible or at least prohibitively expensive to determine in detail up front all of your needs for a software project. At least some of the design and architecture is going to come from “pantsing”, that is, to fly by the seat of one’s pants.

When implementing a new feature, there is usually some experimentation and prototyping going on. In the spirit of moving quickly not necessarily to meet a deadline but to keep one’s thought process flowing smoothly, “Shanty” architecture appears. Shanty architecture where one just bolts something on to see if it works good enough, with more thought on a different plane of reasoning required to determine where that cobbled-on part actually belongs.

Much like we need sleep to reorganize and re-index our brains to keep them healthy, software design needs periods of refactoring to reorganize, re-index, and keep the software healthy. Last weekend was one of these big re-organizing periods. The end result is that the game database is now completely decoupled from the game entities. Originally, earlier in the development of the game, there was little distinction between in-game entities and database entities, over time, the distinction emerged where it was clear that some entities were static and unchanging during game play (database entities), while others were dynamic and constantly updating during game play (game entities). By treating these different categories of entities differently, maintenance was reduced, efficiencies were realized, guidelines became rules, and the whole system became easier to reason about.

While the logical distinction between game and database entities has existed for a long time, some designs that existed before the design rules were formalized continued to violate those rules. This is one form of technical debt. In addition, the lack of a physical distinction that could be enforced through an explicit dependency declaration continued to tempt new designs toward re-coupling the game and database entities.

So it was finally time to enter “REM sleep” mode, re-organize the code so that the compiler could enforce the long-standing rules, and re-design those last few recalcitrant rule-breakers. Now the database has been completely separated from the game entities, and the game entities depend on the database and nothing in the database depends on the game, things are much easier to reason about and I can stop banging my mental shins as I move about the design.

Nearly October Already

The good news is, with the recent changes to the game, it is getting close to a place where I can release and alpha demo toward the end of the month as planned. It won’t be a polished release and there will definitely be things broken, but I want to start getting this game in the hands of more people so that I can judge whether this game will be a good long-term endeavor.

Until next time, be good to each other, and if you haven’t already, be sure to wishlist Dehoarder 2!