22
\$\begingroup\$

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.

\$\endgroup\$

4 Answers 4

30
\$\begingroup\$

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.

\$\endgroup\$
7
  • 30
    \$\begingroup\$ In my opinion, encrypting and signing your savegame files is just snakeoil. It's not secure because you have to store keys and algorithms in your game executable where a skilled hacker can access them. It's also pointless. When it's a singleplayer game: Why bother? Let the player enjoy the game the way they want. When it's a multiplayer game, you should rather save everything on the server where it is safe from manipulation. \$\endgroup\$
    – Philipp
    Dec 29, 2015 at 6:54
  • 5
    \$\begingroup\$ @SamedTarıkÇETİN There's an important distinction between the data path (the location where your game is installed) and the persistent data path (a reliable location to save new data). On some platforms, a built game cannot write to the installed data path, so saving in the persistent data path location is advised as a general rule. \$\endgroup\$
    – DMGregory
    Dec 29, 2015 at 15:36
  • 2
    \$\begingroup\$ While I agree with @Philipp that client-side storage is never truly secure, and that in many cases we don't need to be heavy-handed about securing single-player games, the amount of security or obfuscation to apply is ultimately a choice each creator has to make for themselves. With this answer I just want to give the asker the information to make an informed choice about what's suitable for their game. \$\endgroup\$
    – DMGregory
    Dec 29, 2015 at 15:41
  • 1
    \$\begingroup\$ On the one hand, I agree with @Philipp but I have also seen/worked with a serialized save file that was completely illegible to work with in a text editor. Yes, I probably could have figured out how to go in and make some change or another, but as the file looked like 2 megs of raw hexidecimal it would have been quite the chore to figure out. In such cases only the most diehard of folks would try to disassemble it and the results would be specific to that point in the game (adding one more unit to the save pushes all subsequent data downstream). Then again, it wasn't intended to be secure. \$\endgroup\$ Dec 29, 2015 at 16:02
  • 2
    \$\begingroup\$ @ShantanuSingh by not storing them in PlayerPrefs. That kind of information should be stored in a remote database and requested on app startup. For compatibility when an internet connection is not available, fall back to a local secure saved file (that is: encrypted). The database values, when available, should overwrite the local ones. There may be in-app purchase plugins that handle things in other manners as well, but it'll likely be either "internet required", hackable (even an encrypted file isn't 100% safe), or as this comment details. \$\endgroup\$ Dec 29, 2015 at 21:25
4
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

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 StreamWriter / 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.
\$\endgroup\$
-1
\$\begingroup\$

PlayerPrefs is a K/V store designed to "just work" no matter what platform you build for. I say just keep using it unless you have a compelling reason not to.

\$\endgroup\$
1
  • \$\begingroup\$ I think the question was pretty much if there are compelling reasons not to use PlayerPrefs (yes, there are). As such I downvoted this answer because it doesn't answer the question. \$\endgroup\$
    – Peter
    Jul 9, 2016 at 20:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .