Saving Games

Hi everyone,

I understand that serialization is the best way to save games, but I’m wondering to what “depth” unity serializes. The player and all enemy soldiers are indirectly referenced by a list which stores information about each soldier such as the locations of colliders to do line-of-sight checks against, but not a reference to the game objects of soldiers and the player. I have no idea what the serialization will decide to serialize if I serialize that list. Another issue is that there are destructible objects that are not referenced by any scripts except the ones determining whether or not they are destroyed. Will I have to serialize the entire level?

  • Thanks in advance
  • Steven

Serialization only serializes what you ask it to.

But, remember that you are doing only data. You cannot save references.

You could do line of site checks, but that sounds more like game time management, so it should not be serialized.

When you think serialization and restoration of that data, think: Each item that I serialize can only be data that I can set by a number, string or series of numbers or strings. Because this is how it will be read later.

So if you have 10 different types of units, then you need to enumerate them or give them unique names that your game can identify later.

public enum UnitTypes{
Standard,
Heavy,
Truck,
Tank,
Titan
}

So, now with that enum, you can say UnitTypes.Truck is the unit. This will translate into a string ("Truck") or a number (2). (A string is of course better because you can get the name of the unit, but if the enum changes, then the number may not be right.)

With this, now lets define other values.... Name, HP, Position, MaxHP.

[code]
[SerializeField]
public UnitType type;
[SerializeField]
public string name;
[SerializeField]
public int hp;
[SerializeField]
public Vector3 position;
[SerializeField]
public int maxHp;

// fields that wont be serialized....
public Transform target;
public float fireNextShotAt;
[code]

So, when this script is de-serialized, it will return the serialized values back, and start working from when it was saved.
Things like the target, or timeing of fire, are either not important enough to save, or should be re-calculated using methods on the script.

To answer your question, Unity has a built-in recursive depth of 7 or so for the built-in serializer. That serializer stores all UnityEngine.Objects as references rather than data - so you won’t hit that depth for eg. a GameObject reference.

Knowing that won’t help you save the game, though! You’re mixing up two things here. Serialization is just a concept - take some data, and store it somewhere. Unity’s serializer has very little to do with saving a game, it’s rather the process that saves your Unity project to file.

Unity uses serialization to store all your game’s data - scenes and prefabs and such - and if you have force text serialization on in your settings, you can see how that looks by opening a .unity or a .prefab file in a text editor.

When people talk about serialization for saving games, though, that’s something else. It simply means capturing your game’s state in some format, and then writing that format (serializing it) somewhere. Unity’s built-in serializer probably won’t relate to that.

We can give hints on how to save the game, but how you should go about doing that very much depends on how your game is made. In a game like Ocarina of Time, the game stores your inventory and some specific triggers in the game world - like “has Link visited Zelda in the castle”. Then, when you load the game, it simply figures out how it needs to change the level to fit your current progress.

In something like Oblivion, you can put a sword down on a table, and then come back a month later and have the sword still there. That means that the game needs to save how each level is changed compared to how it was made - I like to think of this as storing the delta of the level. Of course, the game must also save the player’s inventory and all of the save triggers.

1 Like

@bigmisterb : I get that references can’t be serialized, but back when I was coding in Java I could save games by serializing a game world data class which lead to the class instances it referenced being serialized, and the class instances referenced by those classes were serialized, etc. Doesn’t c# serialize a similar way?

@Baste : The depth of serialization shouldn’t be an issue then. I get that you can’t tell me how to save my game, so perhaps I should edit my question to ask: what happens if you serialize data structures that Unity doesn’t control? Unity must be referencing my player and soldier game objects, so what happens when I deserialize the players and soldiers from a earlier save, storing them in my own data structures? Will Unity ignore their existence?

Ah, I’m with you.

So Unity’s, at it’s core, a c++ engine. The C# user scripting interface is a way to interact with that engine.
Everything that derives from UnityEngine.Object - which means all GameObject and all the scripts and components that are attached to them - exists both on the c++ side and the C# side. If you decompile eg. Transform, you’ll see that things like setting the position or parent of a transform is a native call down to c++.

So, if you just try to deserialize your gameobjects directly, the c++ runtime won’t be able to pick that up. The same goes for the scripts and components attached to those gameobjects. So you can’t just directly serialize your players and soldiers, and then deserialize them back.

This is an inherent drawback of the engine. It would probably be possible to take a dumb of the current state of the scene and store it to file, but Unity hasn’t done that. This is probably because those “saves” would be really, really large, and still require you to re-create all of the userspace C# objects that Unity doesn’t know about.

Such a pity that we can’t work with the c++ code. It would be far faster and of course there is the present issue with saving games being much harder than it should be. I’ll just load the whole level again when the player dies rather. I’m doing an assignment and we don’t get marked on saving and loading games, but I thought it would be a neat feature for my game where two shots can kill you.

In almost every case, saving the entirety of the level would be huge overkill. It would be an easy way to save/load state, but not a good one. Also, if the game has an non-scene state like static managers or additive loading from multiple scenes, then that would need to be handled manually anyway.

@Errorsatz : I get that serializing the whole level is overkill, but I wouldn’t be marked on how I save the game so I’m not too concerned about that. I just thought that having saved games would help the tutor get through my demo level.

The best way of saving your game would be to plan your game in a way that you can basically tell it here is the file with data about game state (in whatever form you saved it) in point of time and go trough it and set things like that. Very simply put:)

You would basically need to have some mechanism that would go trough the savegame file and instantiate/set objects and/or values to its right places and values. This depends in great deal on how you planned your game and what it does sometimes this can be matter of recording game object positions and sometimes you need elaborate system that handles many more things and sets the game states so everything is as you left it.

Serializing like Baste already said is something different in theory you could serialize every game object and then reinstate it but that would be huge overkill and still you would have to write your own deserialization logic so you get what you need or optionally create new unity scene files on the fly and then load them (Haven’t tried this one so not sure is it possible).

I would suggest that you just plan your game so it state can be saved to some arbitrary format like XML and then just “serialize” game state in to that file and then read it back and set things as they should be. Optionally you can make save game class that keeps the state of the game and serialize that in to binary and read it back.

As you see many options all depend on how complex is the state you wish to save.

@listener : I wasn’t planning on having a save game feature, which is why I didn’t plan for it. In any case, Unity really should have some kind of generic saved game support, I don’t see how it is practical to save the amount of data that my game tracks since that would involve coding of the saving and retrieval of every single of the thousands of fields the saved games would need to track, and my game isn’t exactly the most complex out there.

A generic save game feature is extraordinarily complex. Serialization of unknown values is a hard problem.

As kru said and also as most of the people here already hinted that save game is not a trivial process at all in the most simplest of games you need to plan it ahead.

But since you have not made plans for it I think you need to do now some creative engineering and see what you can do. If you have thousands of fields already in a game my guess would be that some architecture is in place so try and see how can you use that in your advantage.

Generic save functions typically dump all game state. This results in massive files because it doesn’t selectively store only what’s changed, or try to optimise the way it stores things. The generic way needs to save data structures with references to what datatypes everything is too, wasting space over an optimised binary format. For an example of this going horribly wrong see PS4 games with 300MB+ saves back when the cloud storage was limited to 1GB. It would be particularly problematic on a mobile device where you might not even be allowed to run the save method long enough, because task-switching only give you a second or two to finish up.

So the best solution is to inspect your data and see how you can keep a serialised version as small as possible. Static objects in a scene don’t need any data in the save file, while things with on/off or present/gone states only need a boolean and a reference. Partition it all by scene if it’s a multi-scene game, along with player data. A lot of dictionaries could work. Compress the resulting bundle of data before storing permanently.

The details would depend on what type of game you’re making, but since you mentioned “two shots”, I’ll use an FPS as an example. The amount you’d need to save is fairly small, especially compared to the size of the level:

  1. What level it is.
  2. State of any multi-state objects in the level (doors being open/closed, for example); only if those objects are in a different state than their starting state. Just an int or two per object in most cases.
  3. For existing enemies, their position, facing, changeable stats (health, etc), and AI state; again, only if those are different than the starting values.
  4. For new enemies, their type, plus the same info from #3.
  5. Player state (position, facing, health, ammo, etc).

For steps 2-4, if you have them implement a common interface for this, you should be able to save/load all objects in the scene in an automated way.

I too have been having a plethora of issues associate with saving via serialization because it really isn’t a simple thing – as mentioned above.

I’m trying to make a game that has many similarities dev-wise to Final Fantasy type JRPGs, an I’m in a bind for figuring out what I need to save account or and how to do so. I’d love some input – you guys seem very knowledgable.

How close to the various FF games is it? :wink:

If it’s very close you only need to save which quest in the linear progression was most recently completed, plus the character data. With a purely linear series of quests you just check the number to allow/disallow entry to various things, choose dialog and so on.

If it’s more free-form like a modern RPG you need a method which gathers all the data necessary to save somehow. In a typical FF game there are no real spawned enemies, just encounters, so you don’t have to track anything specific to scenes. In the more modern style you need to maintain lists of everything which has spawned.

Saving is tied to how you’ve organised everything. What do you have, and what have you tried?

In this order: It is in theory quite akin to the older gen. Things like 4-6 (though battle differs in terms of flow and the like).

And yes, that’s fair – roughly what I had considered or knew I’d need to delve into for things to account for when saving.

Really my question is more of a “I do not fully understand how to begin the coding process for this, because I don’t know what things to research and learn”. That seems to be it, anyway – I definitely try to, but I guess I just don’t ask appropriate questions to help me with that :confused:

Now, I have gist of what I have so far, and in it, I have an XML script I used to try and serialize a test player for now.

But then even that opens up a whole slew of questions for me. I’m to the point where I’m getting frustrated with myself and depressive because it seems insurmountably uphill for certain things, and it’s not even about a timecrunch. I’m just trying to learn and have fun with it but gosh, I just can’t get where I need to yet.

I would REALLY appreciate if you or others could take a look and give me some thought out answers as to what is good about it, what is not so good, and where I might consider going from here.

That’s a quite common problem. When we don’t know what we don’t know, we don’t usually know what to ask to know those unknowns :slight_smile:

The trick is to break up your project into small tasks and figure out how to tackle each. I like to think of projects in terms of subsystems, and to make everything as independent as possible. For example, the latest version of my file saving class is just two methods which save and load the contents of an array, and the game needs to serialise to that instead of a file. I now have a generic storage method where I can replace the compression method without breaking actual serialisation.

I think I see what you’re trying to do, but I can think of a few better ways :slight_smile:

How about not making different classes at all for the jobs? Make it more data-driven. Let there just be one Job class, and load the available ones from external data. It can be as simple as just text files with the core definitions (comma-separated values or similar), or you could create a database with scriptable objects. The latter is “the Unity way”, but the former is extremely modding-friendly.

So you would, at the very simplest, have something like this as a typical line in jobs.csv:
Royal Guard,20,0,0,12,6,3,5,.03,0,.7

Load that, split the string on commas and put the resulting data in a new Job object which is then stored in a dictionary by name. You shouldn’t need a whole bunch of classes just for the character’s job. Whenever a character is created with that job you add a Job component to its game object and set the defaults from the job name instead of making a whole setup method for each job.

Saving can then output equally simple data, or you can tailor some XML, or just serialise the Job component and store along with the character’s name.

I added a gist with my simple raw saver, just for fun.

1 Like

Anyone tried JSONUtility to do saving? Its not brilliant, but it does let you hook into Unity’s serialisation system.

You can decouple everything using events if you use them or can implement them in your game.

This is just rough idea since you haven’t planned for save games it is potentially not a lot of change depending on how things work in your game. You can make either base class (this would require more work on changes) or interface like ISaveable and make every object that needs to save its state inherit from it and implement some Serialize method also it should hook to a global event like OnSaveGame and when that event is triggered each object that inherits this interface would “call home” call some SaveManager class that it has reference to (it does not have to it can trigger it’s own event like SaveMe event where it will pass the data that makes it more decoupled but harder to debug) and in return SaveManager would react to all of this calls and compile XML, csv or any other type of file that would in turn be saved.

After this you just need to write some De serialization logic that would read this and return the things in scene as they were.

I’m not sure will this work with your logic but it is one possibility.