Posted January 25, 2025 by Good Faith Company
Hi! I am Ivan Shyika, our Team Leader, Project Manager, and Engine Developer.
Today, I would like to share about the issue of transitioning data between maps in our game and my solution to it.
First of all, why keeping data between maps is a problem? There must be ways to store it, right?
And you would be correct. Some objects exist from when a game opens and until it is closed, regardless of whether you are in the menu or in a "real" game level. The issue, however, is the specific data you likely want to store - for example, the status of your squad - exists not in those perpetual objects but in transient ones such as "actors" located at the game level. When one map/level is unloaded, those transient objects are deleted with all their data. The only way to preserve that data is to copy it into a perpetual object before the transient owner is destroyed.
In our game, a squad of heroes travels from chamber to chamber (our term for "level"). There is a lot of information to keep track of: gold, playthrough time, the count of completed chambers; and above all, information about the squad itself, which is an arbitrary composition of Heroes of different classes in arbitrary conditions (each hero of the squad has their own health and may have died in one of the previous encounters).
Because the squad can be customized, we have to remember the squad composition (i.e., which Hero classes the squad consists of) in such a perpetual object so that the squad can be recreated. In addition, there are also things like health upon completion of a chamber, and we also must have a way not to confuse data between heroes.
So, if the squad is essentially forgotten on chamber completion, how can we recreate the squad at the next chamber seamlessly?
We can use a series of specialized containers that will be stored within one another. Think of it like a box in a box in a van:
This idea of compartmentalization is often referred to as modularity in software development. In essence, a complex system is broken down into smaller, individual chunks ("modules"), which can function independently.
That topmost spreadsheet (Run Data) will be stored in a perpetual object. And since the catalog of profiles (Squad Data containing individual Hero Datas) is stored within it, we have all this data stored safely where it will not be deleted (until the game is closed).
Such a modular setup allows for a straightforward implementation of data persistence and save file systems: if you want to recreate a squad, you only need an instance of Run Data. And if you want to have a history of playthroughs, you would only need to load a list of Run Datas.
There are two key times when the data persistence system is essential: recreating squad on chamber load, and updating squad data on chamber completion.
On the encounter end, we need to update Run Data with up-to-date information on the squad. Updating information is very easy as we have the pointer to every hero stored in their profile (Hero Data).
You may point out, "But what if the hero dies and no longer exists?" That's an important consideration.
If the hero is dead, it does not make sense to recreate them in the next encounter. Besides, their profile will not change after their death, so there will be no need to update their profile either.
And it is accounted for: when the hero is created, the system proactively asks them to let the system know when they die so that the system can mark them as such and invalidate their pointer.
You may be surprised, but in our game, Heroes are so obliging that they always inform the system about their death right before they die, even despite the inconvenience of it. They are true examples of commitment and human decency. Fills you with hope for humanity, doesn't it?
We can now rest assured that any squad data persists across the in-game chambers. Furthermore, you know an example of modularity applied in a real-world case.
I hope you found this breakdown useful, and I thank you for your attention.
Best,
Ivan Shyika
Team Leader, Project Manager, and Engine Developer of Good Faith Team