I am making a game using the Unity game engine. I want to save the player's progress including level, experience points, chosen character, etc. Presently I am using playerprefs but I want to know whether this will work for gamers who will run this game on their mobile devices (Android/iOS) as well as desktops (OSX/PCs)? If not, then how should I save this information? I want to auto-save player progress after clearing each stage.
PlayerPrefs will work cross-platform, but it's not recommended for gameplay progress save files because it's insecure. As a plaintext file, a player can easily open it up and change the contents to cheat, or make your game behave unpredictably. It's also not guaranteed to stay around.
PlayerPrefs is intended for non-essential preference information, like control mapping or music/sfx settings - things the player can freely change anyway, and wouldn't miss terribly if they were to (on Windows for example) use a system restore point and lose some of their registry information. If this lost their high scores or campaign progress, players would be justifiably upset!
Instead, it's recommended to save gameplay progress in your own file (usually binary, possibly encrypted or signed if you want to make it harder to modify, but see Philipp's comment below on this).
You can use Application.persistentDataPath to get a reliable save location on each platform. This is typically in a user data folder that won't be wiped out in cases like the example above.
Once you have a path to save to, you can use the regular C# IO methods to create, write, and read your file. The details will vary a lot depending on your save file format and structure, so if you run into trouble, it's best to ask a new question detailing what you're trying to do and where you're stuck.
On the Unity site, there is a video that goes over the two main options for saving (PlayerPrefs and creating your own save file). The video can be found here: http://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/persistence-data-saving-loading?playlist=17117
Unfortunately Unity does not have a build-in savegame system. So every game needs to develop an own savegame system which is tailored to the architecture and requirements of that specific game. That means there is no "best" way to save data, only the way which is best for you.
When you have very little data to save, then using the PlayerPrefs class can be a quick and easy way to do it. In your particular case, this could be sufficient. But it is intended for, well, preferences. A short list of key-value pairs. It is not designed to hold large amounts of data, and even allowing more than one savegame quickly becomes messy.
So you likely won't get around inventing your own savegame file format which you read and write with the standard C# classes like
StreamReader (for text-based formats) or
FileStream (for binary-based format).
When you only want to save the game state between scene changes, then you only need to persist the data which you already need to handle between scenes. That makes a lot of things a lot easier, because you already have a good overview of what data you have.
But if you want to have a system which allows to save and reload the game at any time, then it gets a lot more complicated. Such a system needs to:
- Find out which gameObjects are currently in the game
- Read any data about them which is worth persisting
- Compile all that data into a file format
- Save that file
- Read that file and parse it
- Recreate all the gameObjects with their components based on the content of the file
- Set their variables according to the content of the file
As you can see from the complexity of some of these points, this is not something where one solution fits every game. But a couple tools that could come in handy for creating your savegame system could be:
- Using the Unity serialization system and see how far it gets you (unfortunately it has some limitations)
- Interfaces which mark a MonoBehaviour as "Saveable" and includes methods which turn that component into a data representation and can set the state of that component from such a data representation. (Unfortunately that won't help you with Unity standard components).
- Behaviours which take care of persisting / restoring all the components on a specific type of gameObject they are on, including Unity-specific components. But that might create quite a lot of maintenance work in the long run.
- Reflection to find out what variables an object has and attempt to persist / restore it automatically
- Attributes to mark variables which should / should not be saved by your reflection-based system
- One of the many save systems you can find on the asset store, which will likely use one or a combination of these techniques.