Making a Pirate Game #4 - Saving Game State

I decided to implement saving and loading the game state. It seemed simple, but unfortunately not in my case. While building the prototype, I had not thought much about architecture, and that turned out to be a mistake.

What exactly do I mean? When saving the game state, I had to account for many different things related to ships (position, speed, cannons, the object being attacked, attackers), as well as projectiles and the states of behavior trees. Unfortunately, that data was scattered across different places in the code, which led to spaghetti code. I decided to fix my mistakes and use the ECS (Entity Component System) pattern, adapted to the specifics of the Defold engine.

Now every object in the game is represented as an Entity with a unique ID. I also introduced entities state, where I collect all the objects that should be saved. Now the user can click the magic “Save” button, and the code will process all entities by calling serialize() on each of them, returning the data to be saved in JSON format :)

Generally speaking, these entities represent object data, and systems process them further. For example, the system responsible for attacks (attack_system) does not need to know exactly what the attacking object looks like. It only checks whether a given entity has a Cannons module, and if it does, it fires projectiles from the cannons. I really like this generic approach: the code is now clearer and easy to extend with more objects.

A tower that shoots? No problem! Just add a Tower class, plus Cannons, Health, and AggressionTracker (which tracks attack targets and attackers). Add textures, a behavior tree, and done!

Oh, and in March it had been a year since I started this blog. Time moves fast!