Developing Dysnomia in my spare time makes the weeks fly by. This week, I'm going to write a little about the level editor behind Dysnomia and how I'm linking together map files, save game files and in-game "devices" which need to keep their status throughout a full playthrough.
The map editor is a functional but clunky Winforms application that doesn't use any XNA, but opts for GDI instead.
It allows the level creator to paint using tiles selected from several tilesheets, one for each map layer. The layers are drawn from the bottom up, starting with the floor tiles, then the walls, then anything overhead. There are a number of in-between layers as well, including separate layers for shadows and decals, which break up the tiled graphics without needing to duplicate tiles. For instance, rather than having "floor tile 1" then "floor tile 1 with top shadow", we simply place down "floor tile 1" in the floor tiles layer, then in the shadows layer we place down "top shadow".
The decals layer allows us to place down little "junk" items like littler, blood spatters, corpses, computer terminals and so on. We have a decal layer for the floor and one for the walls, allowing us to place rubbish on the floor and a computer on a table (tables being wall tiles).
The "specials" layer is used to place items that are replaced in-game with objects. Things like lights, enemy spawns, doors, healthpacks and other pickups all have a tile on the "specials" sheet which is used to represent them in the editor.
The editor also allows us to place down Devices used in the game. Door controls, turrets, terminals and all other interactive objects are placed in this way, and then a few controls allow us to change parameters for each device.
The editor saves each level to a separate text file, which contains grids of three-digit numbers representing a tile number. There is a grid for each layer. After the grids are saved out, additional information about the level is appended - the lighting level, map size and all the information about Devices.
The game will be split up into a number of levels, somewhere around ten in total. This number includes the area outside the mining outpost, on the planet surface. The player needs to scavenge items from the base to repair his ship and thus will need to return to the outside area (and the ship) every now and again.
All of the lower levels of the outpost are reachable via a central liftshaft. At the start of the game, the liftshaft does not work, and requires a number of motherboards to be replaced for each additional floor the player wants to reach. The map layout could be drawn as follows:
Outside -> Entry Halls
When the player crosses between levels, there will be a short pause for loading as the next map is read in and prepared for use. However, because the player can explore the entire base at will and return to any previous area at any time, we need to hold a state file on all the objects that the player can interact with. This state file will stay active from the start of a game until the player dies or finishes the game. The same state file will also be used for loading and saving games, so it must hold information on the player's status too - current map, position, health, weapon powerups, ammo etc.
I decided to wrap up all this information in a single class that is instantiated at the beginning of play. The class has its own Load() and Save() methods. The Load() method takes a string as the only argument, the string being the contents of a saved game text file. The Dysnomia editor has a generator to create a save file that represents the intial state of everything in the game. If a player starts a new game, it will be that file that is supplied to the GameData class, essentially creating a "new save" in memory.
Throughout the course of the game, the GameData class will be updated to reflect the current state of the game. For instance, if a player takes a motherboard out of a device, that device will be updated in the GameData class to show that it holds one less motherboard. The GameData class also holds the number of motherboards currently held by the player, which would be incremented at that point.
Some data in the GameData class will only be updated when the game is physically saved. The player's health, level and location would be some examples, as would the location of any enemies currently on screen. I feel that on the whole, it's a solid way of dealing with saving game progress, especially given the open-ended exploration nature of the game.