3 min read
Data Driven Architecture

So, how to do saving/loading? Serialization is a good option, which led me down the path of improving object data.

Skymagi uses an Entity, Component, System (ECS) approach for organizing gameplay mechanics. An entity is really just a bag of components. So for storing an entity, I just need to store its components.

And entities are not just Mages.

  • Areas (with tiles) are entities that can be traversed.
  • Enemies, like wolves
  • NPCs
  • Sounds
  • Quest data
  • Animations

Which means if I can serialize all my components, I can serialize my entire game.

I chose to use JSON rather than a binary format for ease of use, but could change that in the future. Here’s an example mage:

{
  "TypeComponent": "mage",
  "PositionComponent": {
    "x": 13,
    "y": 13
  },
  "SpeedComponent": 5,
  "HealthComponent": {
    "max": 100,
    "hp": 100
  },
  "CommandableComponent": {
    "selectable": true,
    "moveable": true
  },
  "AnimationComponent": {
    "states": "battlemage",
    "state": 0,
    "isLooping": true
  },
  "TextureComponent": {
    "atlas": "spritesheets/game.atlas",
    "name": "mages/battlemage/battlemage-idle",
    "hidden": false,
    "width": 1.8,
    "height": 1.8,
    "offsetX": 0,
    "offsetY": 0
  },
  "BodyComponent": {
    "width": 1.5,
    "height": 1.5
  }
}

This is all a mage is currently (I regret adding “Component” to all my components). All objects in the world can be represented by their aspects, which makes extending and adding objects easy. Usually they just remove features, like a rock.

{
  "type": "core.props.rock",
  "PositionComponent": {},
  "TextureComponent": {
    "atlasId": "game",
    "regionId": "props/rock_64x64",
    "width": 1,
    "height": 1
  }
}

Now that saving/loading is easy, I could extend my entity system so that I can load prefabs and then manage data for my mages, props, and other objects rather than defining them all in code.

So I added a system that will load up JSON definitions and allow me to override properties (like x/y location) when I create a new entity.

And just for a bonus, I added this idea of a “prototype”, where you could have a parent. For example, the Necromancer.

{
  "prototype": "mage", // extends "mage" definition
  "TypeComponent": "necromancer",
  "TextureComponent": {
    "name": "mages/necromancer_48x48"
  }
}

Adding new objects is now easy. Later, I’ll flesh out the prefab system more.

New Concept Art

Our artists have been playing around with what a castle might look like:

Castle Concept