Adding persistence to the city environment

posted in: Dev blog | 0

While working on Trespassers, one of our concerns was persisting data between different levels as they were loaded. For instance, if a player spends too much ammo, he may run out of it, and we wanted to store this change as he has to manage his money in order to fill the weapon again. We are using Unity3D, so it could be easily achieved using PlayerPrefs, a helper class to store/load data between game sessions, and as this is a rather small info to be loaded, it would be straight to prototype and test it. But┬ámanaging player’s inventories got a bit more complicated, so we opted for a different solution using DontDestroyOnLoad, and that eased the development.

In this case, our problem was that, as the city can be partially destroyed, players could enter a mission, finish it, and then go back to the overwold map. It would feel a bit weird if the destroyed buildings were reconstructed. What is more, this would affect gameplay, as players may destroy buildings to create paths across the level. And as the buildings were randomnly created, we had to:

  • Construct the city with the same buildings
  • Keep destroyed buildings destroyed

Maybe the first one doesn’t seem necessary, but it is. Players may use some buildings as reference points. Buildings are big, will not move, and some of them are distinctive. Thus, buildings are used to let the player take some references about interesting places. So, if we change the layout, players may feel confused. And obviously, it would be hard to justify that a destroyed building is no longer destroyed.

By the way, you may have noticed that we have added more variation to roads as well.

Our solution

How we kept the same buildings: when we create an area of the city, we shuffle an array of buildings loaded, randomnly selecting them to be placed in a regular grid. The layout is given by an internal representation, currently a small bitmap, which is easy to produce, understand and ultimately debug, if needed. It is not as flexible as we would like to, but more info can be easily added to it, so it fits our needs.

Overworld bitmap
This sprite represents a whole city

As the objects are loaded in the same order, the simple trick is to store the index of the randomnly selected object, and create it later using the same index. We are not currently storing everything, just buildings, although the process would be the same for everything else. So, for a level made of 120 x 80 tiles (rather big for our game), storing one int per position means storing around 9 KB. The process of reconstructing the city gets a small boost, as the index is red directly instead of calculated for each tile. Win!

How we kept buildings destroyed: as you can imagine, the process is quite similar. We store the damage done to every building in the same way. When a building is destroyed, there is an object (prefab) that is used to replace the previous building with a new one. Others, as they get damaged, just change their appearance. Before the level gets fully loaded, this value is updated for every damaged building, so buildings are replaced on the go, and the player gets back to the city as he remembers it.

Of course, some cars may have changed, some new enemies may have appeared, but that is quite acceptable right now. Even, in the case of enemies, desirable, as the city keeps alive while the players are away.

See ya!


Leave a Reply

Your email address will not be published.