Spiders! Data-driven Spiders

Airships: Conquer the Skies
21 Oct 2015, 4 p.m.

With dev 7 and its revisions complete, I am now fully engaged in working on the next major version of Airships. This time, the big addition is going to be monsters, and to make that happen I'm doing a lot of cleaning-up and restructuring.

All units, including the upcoming monsters - dragons, fleshcrackers, suspendium bees - are handled in-game as "a kind of airship" or "a kind of crew member". Obviously, buildings are just airships without lift and propulsion, and landships ones with an alternative propulsion system. I can reuse the code for handling a lot of stuff - movement, collision, shooting, targeting - for creatures as well. A fleshcracker is just a funny-looking small landship, an aerial kraken is just an airship with no crew and a special tentacle attack.

So what distinguishes the two kinds of units?

"Airships"

  • Large
  • Can be composed of multiple modules that can take damage independently
  • Can have interior spaces containing crew and boarders
  • Collide with each other
  • Dimensions must be a multiple of grid size

"Crew"

  • Small
  • Have a single hit point pool
  • Can board "Airships"
  • Can overlap

Right now, I'm working on the latter kind of unit, taking code originally written for humanoid crew members and making it more flexible to accomodate, say, giant spiders!

At the same time, I'm also moving all the information associated with crew types - their stats, what they look like, their animations - into JSON data files. This has two major advantages: it lets me better organize the data, and it opens the way for people to create mods for the game that don't need to patch the game code.

When I started writing Airships a bit more than two years ago, I was really just gluing together a prototype, and so I heavily relied on a Java feature called enums. These are handy if you need to have a short list of options with a bunch of properties, eg:

public enum Weapon {
    DAGGER(5, 1, 3),
    SWORD(8, 2, 10),
    BOW(6, 10, 7);
    public final int dmg;
    public final int range;
    public final int cost;
    private Weapon(int dmg, int range, int cost) {
        this.dmg = dmg; this.range = range; this.cost = cost;
    }
}

But once your game becomes more complex, the fact that you create enums by specifying an unlabelled sequence of values becomes unmanageable:

Can you read this and figure out what's going on? I can't really, and I wrote it!

So instead, game data like this should reside in an external data file, as JSON or XML or something. For the example above, this looks like this:

[
    {
        "name": "dagger",
        "dmg": 5,
        "range": 1,
        "cost": 3
    },
    {
        "name": "sword",
        "dmg": 8,
        "range": 2,
        "cost": 10
    },
    {
        "name": "bow",
        "dmg": 6,
        "range": 10,
        "cost": 7
    }
]

Far more verbose, but more readable. And because it's just a text file, you can write tools to work with it too. Case in point: I moved all the information about crew animations into data files, and then wrote a simple but very nice in-game animation viewer that lets me see the animations in action. I can also reload the data files instantly to see changes, which means I can iterate quickly between making tweaks in the data and checking the results. Of course, this isn't quite as nice as as proper GUI animation editor, but it's a lot better than having to restart the game each time!

So I've been working on my new, data-driven spiders. Like crew, they can enter ships and jump between them, and fight other crew members. Unlike crew, they can't operate ship modules, and they look... rather different.

What's next? There's a lot more stuff that needs to be moved into data files. The list of module types is the big one, but there's also armour types, particle types and smaller stuff like module categories and coat of arms charges. Not quite everything can be transformed in this way. Anything that needs custom code, for example bonuses like "+25% income from cities", can't be purely data-driven.

And on the content side, while the spiders are mostly complete, there's a bunch more code that needs adding to support the behaviours of other small monsters, such as flight and the ability to attack airships.

As you can tell, there's a lot left to do for version 8. It's at least as complex an update as version 7's landships, and you know how long that took! To tide you over until then, I'll be doing regular blogging: technical dev updates like this, lore backgrounders, and posts about cool related stuff I find in my background research.