A company recently asked me about a challenge I’d overcome while making games. I wrote a response and then discovered it was five times too long. Oops. Well, instead of throwing out the response, I’m turning it into a blog post here.
SELF DESTRUCTING WOLVES
I previously wrote about the self destructing wolves in a previous post, but I’m including an abbreviated version here to consolidate some interesting challenges. The longer version can be read here.
This is an old one, but remains one of my funniest game development memories. I was working on a game many years ago, a roguelike, in which players would explore a world and encounter enemies. The enemies could be one of any number of factions, such as wolves, orcs, thieves, etc.
Some of those factions were allies, some of them were enemies. Allied factions would help each other, enemy factions would attack each other on sight. To implement this, I re-used code I had written to make enemies attack the player, and added logic to check for NPCs on screen, in addition to the player.
So I wrote this code, and started the game, loading a map that was filled with wolves. As soon as I loaded the map, all the wolves killed themselves. I was stunned, all the more so because it was about 2am. I refreshed, and again, all the wolves immediately killed themselves. The combat log read “WOLF ATTACKS WOLF, WOLF DIED.” At that hour, after that marathon dev session, this felt like the manifestation of some strange existentialist metaphor.
The problem, it turned out, was that when I had implemented the code checking for enemy factions, I had set it so that factions without specified relationships would treat each other as enemies. So if they were not friendly, they would always be treated as enemies. The problem lied in that factions didn’t have relationships with themselves. So because the wolf faction wasn’t allied with the wolf faction, everyone in the wolf faction would immediately start attacking the wolf faction—which meant every wolf immediately self destructed. The fix was one line: include in the if statement that checked if factions were enemies a check that prevented the unit’s own faction from being treated as hostile.
THE OREGON BAIL
I was recently working on a fantasy re-imagining of The Oregon Trail. What began as an excuse to draw some sword-and-sorcery pixel art of dwarves and wizards quickly grew into a functional prototype where you could travel down a road, encounter NPCs, find items, and contract dysentery. Initially, I thought it would just be a small demo, so I chose Game Maker Studio 1.4 as the engine—it was what I had been using for Teatime Samurai for legacy reasons, despite its deprecation for several years.
After building the weekend project version, I really liked the results and decided to keep going. I figured that since I had already put in so much time, I might as well stick with Game Maker. However, I quickly ran into some significant limitations.
The first issue was that, if I wanted to build a large number of encounters (decision-tree events randomly encountered along the trail), I would need to structure them as data, rather than hard-code the logic for each event. In other languages or engines, this would be straightforward—many are well-suited for this type of task, where you could implement encounters as instances of a class. Even better, you could define them using JSON or another data interchange format.
I chose JSON because it’s readily understood by many languages, and I could build a tool to graphically create encounters outside of the game engine, then export them as JSON for the game to parse and load as events. I built the tool in such a way that non-coders could create their own encounters. Great! The game was moddable right out of the box!
But the real challenge came when trying to handle that JSON in Game Maker—and what a problem it was. Aside from memory issues when using maps and lists in Game Maker, the syntax for accessing them is incredibly cumbersome.
For example, let’s say I wanted to access an ability in a unit’s ability list and retrieve its damage. In a more competent language, you could access a nested property with something like:
damage = unit["abilities"][2]["damage"]
However, Game Maker doesn’t offer these niceties because we don’t deserve them. Instead, you have to do something like this:
abilities = unit{? "abilities"} secondAbility = abilities[| 2] damage = secondAbility[? "damage"]’
You can’t chain accessors in Game Maker Language. So, with deeply nested properties—something you’d certainly encounter when building complex structures like the ones I needed for the game’s encounters—you end up with massive amounts of ugly, difficult-to-read code.
It should have been a red flag when I found myself creating my own solutions to problems like these—in this case a script that let you traverse properties like this:
traverse(unit, "abilities", 2, "damage")
This required a lot of iteration, type checking, and undefined value handling. The fact that this basic language feature was missing should have been a clear sign that Game Maker was the wrong tool for this job.
Using a number of these wheel reinventing approaches I was able to fully implement the code to parse the complex JSON structures generated by the GUI tool I built, but by the time I had completed this implementation it was abundantly clear that this was not a viable long-term approach for performance and maintainability reasons. Still, it was a fun project to explore ways to overcome specific limitations like these and to develop a greater appreciation for shall we say, more elegant languages.