Tales of the Rampant Coyote

Adventures in Indie Gaming!

Programming: Algorithms, Deltas, and Exceptions

Posted by Rampant Coyote on December 18, 2012

Sometimes I am a little slow, and need to be taught a lesson a number of times.

My very first day on my first game development job, I was confronted with the design document for the game that would one day be Twisted Metal (actually, I was introduced to both that doc and the Warhawk design doc the same day). Within were tons of meticulously generated spreadsheets describing all kinds of discrete situations and responses for each of the AI-driven vehicles. The idea was quite sound (listen up, designers!): They had a vision of a particular gameplay that they (I think I’m speaking of Dave Jaffe and Mike Giam, though they may not have been the only ones involved) had in mind and wanted to make sure was reflected in the final product, and they wanted to make sure that the AI felt unique and interesting.  Fighting Sweet Tooth should be a fundamentally different experience from fighting Yellowjacket, requiring a different approach based on not just the vehicle strengths and weaknesses, but also upon the AI tendencies.

I won’t say these spreadsheets were useless. And maybe they were never intended to be dropped directly into the game as-is – that was simply our inexperience at work. They guided our work on the AI, certainly. And we did implement the chart as best as possible. But there were problems with this approach:

#1 – In the real game, things were a lot more fluid and a lot less clearly defined than would ever be reflected in a spreadsheet. Often several of the conditions (or none of them) applied, or the difference between them got really ‘fuzzy.’

#2 – In the real game, a lot of what sounded cool or interesting or useful or even perceivable on paper proved to be… not.  For a concrete example, look at all the rear-firing weapons that were not really included (except in some cases via special moves) in the sequel.  While they could kinda-sorta be used to help shake off pursuit (or at least make sure they couldn’t chase you with full impunity), they were difficult to use and the actual gameplay didn’t turn into long running battles in one direction.

#3 – In many cases, the logic for the physics and behaviors were best handled algorithmically rather than through discrete states and behaviors. As an example – if you have unlimited ammo and no gun overheating and a pretty constant stream of bullets available to you, then there’s no penalty at all for just leaving the machine guns on whenever a target is in range and front of you. It’s how humans played. So to have the AI deviate too much otherwise would unnecessarily cripple the AI skill.

#4 – If you had to make a major change to the game logic or balance, it involved going back and changing a whole ton of values. This made changes a pain, and it made experimentation very slow.

So what really happened is that we distilled all these tons of spreadsheets into some nice, algorithmic behavior with a few meaningful parameters and exceptions (I’m talking exceptions from the general game rules, here, not code exceptions). These rules were driven by spreadsheet values initially, and later tweaked when the game was fully playable.  The algorithms provided a great course level of control – for handling general behaviors across the board, and balancing the game as a whole. The little exceptional, specific situations gave us the personality.

While my total budget for Frayed Knights wouldn’t have paid for a week of development of many of the games I’ve made in my career, it was also in most ways the biggest, most complicated game I’d ever worked on. And it is also my favorite (so far…), something I was really excited to create, which was probably part of why I lost sight of old lessons. I’ve had game designs buzzing through my head for how a “proper” RPG system should work ever since I first started playing Basic Dungeons & Dragons, and in spite of having played tons of CRPGs, it was the old dice & paper rules that informed my design decisions. This was mostly deliberate – I wanted Frayed Knights to be as much of a return to the feel of classic dice-and-paper gaming as to old-school CRPGs.

The thing is, human-moderated rules really are a whole different animal, by necessity, from computer-driven ones. Just as you’d not want to make a movie that is simply a scene-by-scene recreation of what is described in a book, making a computer RPG directly out of the rules of a dice & paper game is pretty sub-optimal. And making a new game system for a CRPG with too much devotion to the way the dice & paper games do it is likewise less than ideal. Again, it comes down to all those charts and tables – what passes f0r a spreadsheet in a human-moderated game. We humans don’t do complex calculations in our head very well… having the numbers out in front of us in chart form is much easier.  But for a computer, those calculations and algorithms are simple.

A mistake I made was defining all these charts – in spreadsheet form – and putting them all in the game. The silly part of it was that I generated much of the data in the spreadsheet algorithmically – to keep things balanced. Why generate a pile of numbers, tweak them, and then enter them all individually into the game? Why not only generate the tweaks – the deltas and exceptions  – from the norm?

Consequently, I ran into all the problems I listed above – the data didn’t respond well to changes or make it easy to experiment; and as the game evolved, multiple changes were necessary. And many of those items that I so meticulously entered, tweaked and re-tweaked, and maintained through multiple revisions turned out to be pretty useless in the grand scheme of the game. Certain statistics had such little impact that they were lost in the noise.

So again, the lesson is this: keep as much of the overall game balance in simple, global parameters for algorithms.  Define the unique elements by their deltas and exceptions (again, game rule exceptions, not code exceptions) which can scale with the global changes.

For example, lets say your average sword does 8 points of damage – a value cribbed just now from good-ol’-fashioned D&D. The wrong way to do it (hello! This was me!) is to have a magic sword listed as doing 9 points of damage.  What happens if you change the average damage of a sword to 10? Suddenly your magical sword becomes a defective sword. A better way to handle it would be to define the sword as doing +1 additional damage.

But then, what if you multiply hit points across the board by 10, so that a normal sword now does 80 points of damage? Suddenly this +1 sword sounds pretty pathetic. An even better, more scalable approach would be to list this weapon as one that does +12.5% more damage than normal.  But then there’s still another problem – what if you actually reduce the average sword’s damage from 8 to 4? Now +12.5% damage is only a half a point, and if you don’t round up, then this means your magic sword is no better than a normal sword.  So you could even go one level further, and say this magic sword has a “Low Level Upgrade” on damage, and let “Low Level Upgrade” be an algorithmically determined modifier.

Of course, you can get absolutely insane with these generalizations, and they can come with their own problems. The important part is keeping things scalable and easy to change.  Games are not just interactive in the final product – the process of development is (and should be) highly interactive as well, with lots of changes and improvements and balancing and tweaking and p0lishing as a constant process. Giant charts of discrete data with tons of foundational interdependencies is pretty much the opposite of how you want to develop your game.  Keep your data-driven aspects hierarchical and solved at as high a level as possible, and keep the low-level stuff for making things special and cool.

Good luck, and have fun.

 


Filed Under: Programming - Comments: 4 Comments to Read



  • Joel Davis said,

    Very interesting post. Do you think it would work to still use a data/spreadsheet-heavy approach, but build the generalizations into the spreadsheet rather than the game? e.g. just make your “magic sword” cell use a spreadsheet formula rather than directly listing “9”? I like keeping the game code itself very sparse — i.e. it just takes a table of weapons and damage values — but building this kind of algorithmic tuning into the spreadsheets seems like a good idea.

  • Albert1 said,

    This is one of your best posts ever! It reminds me why this is the only blog I read every day: on programming/technical stuff no other indie blogger beats you!

  • Rampant Coyote said,

    @Joel – Actually, what you suggested is pretty much what I did for FK2. One problem was that I didn’t have things automatically import in the game (via CSV or something like that), which meant I had to manually cut & paste the results. But that’s a technical problem that could be resolved.

    The process problem is a little more subtle and more dangerous: Code and the data the spreadsheet produced ended up becoming primary documents – and often changes got made to the game that didn’t get reflected into the spreadsheets until much later. So the spreadsheets weren’t guaranteed to be up-to-date until I worked backwards.

    Another issue with this is that sometimes the changes made to the game were not something that could be easily updated in a spreadsheet. At best I could search for certain values in certain fields, and then hand-tweak other fields for those entries. As a (mostly, as far as you know…) made-up example: Lets say you have a field called, “Armor Piercing” in your game, and you build all your tables with some weapons having a greater armor-piercing values than others. You’ve taken great pains keeping lots of weapons with various armor-piercing values in the game, and you’ve balanced all of your weapons accordingly. Then, later, you decide to remove that aspect from the game entirely (because it’s too hard to balance, or useless, or whatever). Now you have half your weapons that are now weaker (at least on paper) or too expensive because they were balanced around the Armor Piercing stat being so important. So now you have to go through pretty much every stat for every weapon in the game and re-tweak them according to the new game rules to keep them more-or-less ‘in balance,’ so that half your weapons don’t seem pathetically underpowered or overpriced.

    When your weapons are all listed as just deltas from a standard formula, you could just look at all the weapons that were set to “Armor Piercing = true” and tweak one field up or down respectively to rebalance everything. In theory, it could be just as complicated, but in practice it tends to be a lot easier (and as a bonus, it encourages you to keep playing with the rules and be willing to make changes where they seem appropriate).

  • CdrJameson said,

    We used to use a lot of automated tests in our games to try and make sure we hadn’t broken the balance.

    Some features were always supposed to score more than others, and so we’d have a little test in there to make sure they did. This wouldn’t fix the magic sword example above, but it would alert you to a problem where your magic sword was no better than a normal one.

    And when we used spreadsheets (or databases) we always made sure that the first stage of the build process was to export the data from the application into a source file – then we always knew that the spreadsheet was the master copy, and the source-code just derived. The derived files weren’t source controlled either.

top