Data driven ships

Posted On 7 Jun, 2015

In which I rant about what I’ve been tinkering with.

I’m making a new system for ship designs and how they interact with the save game format. The end goal is to make unlocked ship designs data driven so that ships, and things resembling ships, can easily be added to the game world through extensions and mods. It will also make it easier for us to add content to the game.

How ships currently work

A ship is actually very data driven at its core because 99% of the information that makes up a ship comes from 2 images representing the top layer, and the bottom layer of the ship.

The top layer has artwork and interacts with the other tertiary layers (emission, specular, normal) to make the ship look pretty, but it also has function in the sense that each pixel of the top layer is a physical entity that maps to a tile on the inside of the ship and can absorb damage to protect your crew and modules.

The bottom layer is a map with colors representing module type and placement. It allows the game to procedurally map the interior of any ship that you enter. When any crew member exists inside a ship, be it your avatar or AI crew, the game reads the contents of this bottom layer and creates the interior of the ship from it. Thus ships can have very complex interiors and still only take up the memory of a single sprite when nobody is inside them.

So when I create a ship entity in the game, all I need to do is hand it a set of images and it constructs all the data structures for me. It’s easy to get those images from the built in textures, or from a user profile directory or wherever, since they are just images. However in the game itself we often want to spawn the same ships over and over again from a template and then we want to capture them and unlock them so the player can spawn them, and this creates a strange problem: The game has no idea if two ships are the same ship once they are spawned. So now we have this issue where an SSC battle cruiser (for example) is obviously the same ship design every time you encounter it, but the game needs some way to know that when you try to unlock it a second time.

My initial solution to this problem was very simple, as my first solution for things tends to be. I simply created a bunch of templates for ship types in code by mapping top layer to bottom layer in a data structure and assigning them an ID. When a ship spawns it just remembers its ID, and if you try to unlock it you just unlock the ID. That system is really easy to check for duplicates, but it requires the ships to be declared in code, or at least for the associations between layers to be declared in code.

Then I started making extensions, and as I added more and more level generation stuff into extensions it became obvious really quick that I needed a new way to represent ships so they could be spawned from extensions.

New system

So I’m making a new system where the image itself is the unique identifier for a ship hull.

It’s going to take some fancy math to compare images, and it will probably be fussy about ships with single pixel differences, but in the long run I don’t think that will matter. The new file system stores all unlocked ship designs inside a fancy new binary format. It’s going to be part of the world save. The game can recognize if you encounter the same ship multiple times no matter the source of that ship by comparing the source artwork, and it can group custom designs for a ship based on the top layer artwork those designs are made for. So essentially when you unlock a ship hull the game is looking at it, and deciding if it has seen that image before. That means you can take any old image, drop it into a single player game, and it will be treated as ship class, instead of as a blob of pixels, allowing you to spawn multiple copies without making everything confused.

That means a number of things will be possible in the future:

  • Ship design in single player is possible now since we have an effective way of storing both a player submitted design and a built in one.
  • The game can easily keep track of an unlimited number of interior designs for every hull you unlock, so you can update a single design every time you find new modules or keep every revision as a separate ship in case you feel nostalgic some day.
  • Ships will be easier for us to add and I can toss out a lot of that wasteful code mapping designs to ID values stored in memory all the time.
  • Mods and extensions can add custom ship hulls as easily as making artwork for them and picking a spawn location. (or spawn algorithm) I’ll try to make a sample extension that lets you simply drop art into a folder.
  • Tech savvy folk will be able to extract unlocked ships from their save games and move them around.
  • Ship hulls and designs should be version neutral. That means ships added by mods should have no issue existing in the vanilla game.

I’m already about half way done designing this system now. I’m at the phase of going back through the old code and replacing references to integer ID spawning with the new hull system. Overall this brings me a big step closer to my ultimate vision of being able to copy paste an image into the game and have it turned into a procedural world for you.