The concept of saving and loading can be a daunting one, both with the impending fear of implementing the thing properly, but also with either a distinct lack of information, or an abundance of misinformation on how it works.

Well, fortunately – I thought I’d cover this topic in detail, so that should you ever need a guiding hand, you can use this as a reference to implement your own systems. I’ve split this particular tutorial into two parts, Player Prefs, and Serialization; for better readability. This part contains Player Prefs, with Serialization coming soon.

So without further ado let begin covering the first of the two types of saving and loading within Unity, PLAYER PREFS.

Player Prefs

Player Prefs is a platform independent means of saving, that’s incredibly quick to implement, and consistently reliable, which is the main upside of using player prefs in your game. The downside, is that it’s not entirely secure, and unfortunately should someone be determined enough to break into it, they can. It also can only handle a certain number of data types.

So if your save information contains non-sensitive information, this is an entirely ideal method for you to use, or even practice with in development – however, if you find yourself saving information that may pertain to monetisation availability etc, then you may want to skip this part, and go to SERIALIZATION (coming soon).

Implementation of Player Prefs

Let’s suggest in our exact example, we are making a fantasy game, where you can name your character, and for every orb you collect, you increase in power by one.

Meaning that we want to remember how powerful our character is, and also we want to remember their name.

Well, in this exact example we only need to save our name once, and simply reference it later. So let’s take a look at the code we would need to implement that.

** To create an example that will allow you to follow on with this tutorial, perform the following steps:

Create a new project and a new scene in Unity. Call both the project and scene whatever you feel like.

Go to the GameObject Menu at the top of the screen, and select Canvas. Set the Render Mode to Camera, and set the Camera to the Main Camera in the scene.

Click on images for a better view





Click on images for a better view

Right-Click on the Canvas you created and Navigate to UI. Create an InputField, and position it somewhere the Canvas that you can see. Also, Create a Text GameObject, and equally position it somewhere you can see, ideally above or below the InputField you created. Place a Button somewhere and change the text to something like, “Get Name”.





Click on the GameObject Menu at the top again, and then Create an empty Game Object. Name this something memorable, like “CharacterNameController”, and add a new script component, called “CharacterScript”.

Open up the CharacterScript and paste the following code. Save it.

Back in the inspector, drag the Input object you created, onto the script characterInput, and drag the Text object onto the script characterText.

Click on the InputField you created, and under End Edit, click the little plus sign. Drag the CharacterNameController object you created onto the new function you created. When you’ve done that, click on the assign script section next to it, and select InputSet().





Click the button you created, and under OnClick, click the little plus sign. Drag the CharacterNameController object you created onto the new function you created. When you’ve done that, click on the assign script section next to it, and select InputGet().

This should be your scene set up, so that the following code can be demo’d.

I’ve shown the full final code for editing the character name, below, and then following that, I’ll break it down, section by section.

using UnityEngine; using UnityEngine.UI; public class CharacterScript : MonoBehaviour { public Text characterText; // The text object where we display our characters name public InputField characterInput; // The input object where we type our characters name private string characterName = ""; // Private reference to our character class private const string CHARACTER_NAME_KEY = "CHARACTER_NAME_KEY"; // Set a CONST value to avoid spelling errors in save file private void Start() { InputGet(); // Display the character name. } /* * Here we get the player name, and return it, from any location * it exists. If it doesn't exist anywhere, we will still return * blank, but leave a debug for us to know why blank was returned. */ private string GetCharacterName() { if (characterName != "") { // If we don't need to load, don't return characterName; // return the character name } else if (PlayerPrefs.HasKey(CHARACTER_NAME_KEY)) { // If the playerName has been saved before and exists characterName = PlayerPrefs.GetString(CHARACTER_NAME_KEY); // Set the characterName based on the name in our save file. return characterName; // return the character name } else { Debug.Log("Player name has not been set yet!"); return "Enter Name"; // return placeholder, but submit a warning so we know why a name wasn't returned. } } /* * Set the character name, based on the string provided. */ private void SetCharacterName(string name) { characterName = name; } /* * Save the character name in our save file. This is separate from save, because we might not ALWAYS want to save the name to a save file, but we would still like to set it at runtime. */ private void SaveCharacterName(string name) { PlayerPrefs.SetString(CHARACTER_NAME_KEY, name); // Save the characters name, using the key 'characterName' and setting the value to the provided string value of name. } /* * Deletes the characters name. */ public void DeleteCharacterName() { if (PlayerPrefs.HasKey(CHARACTER_NAME_KEY)) { PlayerPrefs.DeleteKey(CHARACTER_NAME_KEY); } else { Debug.Log("No save file to delete!"); } } /* * This function will actually start the process off. It allows us to keep the rest of the code private, and our variables secure. */ public void InputSet() { string name = characterInput.text; SetCharacterName(name); SaveCharacterName(name); } /* * This function actually allows us to grab the information. */ public void InputGet() { characterText.text = GetCharacterName(); } }

And that’s it!

Now, load up your scene, and it’ll grab your previous characters name. On your first time loading, we’ll be given the default placeholder of “Enter Name”.

When you type in a name, and it’ll automatically be saved to the GameObject, and then saved via Player Prefs!

Scene Before Playing

Scene On Load

Typing Name

After Pressing Button

Breakdown

So what exactly is going on here, and why do we need what we need? Well let’s take it bit by bit.

using UnityEngine; // For Player Prefs using UnityEngine.UI; // For the UI Elements public class CharacterScript : MonoBehaviour {

Player Prefs is built in to the UnityEngine, so to physically get it to work, that’s all we need to include at the top of our file. However, because we use UI elements to access our functions, we must include the UnityEngine.UI namespace to get access to it’s methods. Public class CharacterScript : MonoBehaviour simple declares our class, which our object becomes an instance of.

public Text characterText; // The text object where we display our characters name public InputField characterInput; // The input object where we type our characters name private string characterName = ""; // Private reference to our character class private const string CHARACTER_NAME_KEY = "CHARACTER_NAME_KEY"; // Set a CONST value to avoid spelling errors in save file

The characterText holds our Text UI object in the Editor. InputField holds the InputField UI object. Because both of these are dragged into the inspector (in our example, but there are other methods of doing this also), then we must keep them as public variables.

The characterName will holds our actual character name. We need to declare this in the global space (at the start of our class) so that it can be used in other functions. The CHARACTER_NAME_KEY simply holds the string CHARACTER_NAME_KEY and cannot be changed. This simply allows us to reference the PlayerPrefs data file, using this key name – without ever accidentally using spelling errors. i.e. If we didn’t do this, then we increase the chance that somewhere in our code, instead of looking up “CHARACTER_NAME_KEY” we may accidentally try to look up “cHARACTER_nAME_KEY”, or more realistically if we forget, “characterNameKey”.

private void Start() { InputGet(); // Display the character name. }

We grab the character name on start to save us a button press. You can leave this out if you’d rather demo by pressing the button.

/* * Here we get the player name, and return it, from any location * it exists. If it doesn't exist anywhere, we will still return * blank, but leave a debug for us to know why blank was returned. */ private string GetCharacterName() { if (characterName != "") { // If we don't need to load, don't return characterName; // return the character name } else if (PlayerPrefs.HasKey(CHARACTER_NAME_KEY)) { // If the playerName has been saved before and exists characterName = PlayerPrefs.GetString(CHARACTER_NAME_KEY); // Set the characterName based on the name in our save file. return characterName; // return the character name } else { Debug.Log("Player name has not been set yet!"); return "Enter Name"; // return placeholder, but submit a warning so we know why a name wasn't returned. } }

The GetCharacterName method could be simplified, in order to perform the function and nothing more, but I’ve tried to write the code as close to a real-world example, which would have to include some error handling, as we can’t have our entire game breaking, just because there was an error grabbing the players name!

Because this method is of type string, we’re expecting a return type of string. This is why characterText.text = GetCharacterName(); works later on. So would string test = GetCharacterName();

We then immediately hit our first check. If the characterName on the gameObject is not empty, it must have been set! If so, we return this name, and that’s the end of it. If however, it IS empty, it may simply mean we’ve not grabbed it yet. So we check to see if a Player Prefs Key exists, i.e. has the characterName been saved, but we’ve just not set it in this instance. If that’s the case, then we get the character name from Player Prefs and use it to set our objects characterName. If however, there is no player key, and it’s not been set locally in the game object, then it hasn’t been set, and we can return any string we please to alert the user to this. For our example, we used “Enter Name”.

/* * Set the character name, based on the string provided. */ private void SetCharacterName(string name) { characterName = name; } /* * Save the character name in our save file. This is separate from save, because we might not ALWAYS want to save the name to a save file, but we would still like to set it at runtime. */ private void SaveCharacterName(string name) { PlayerPrefs.SetString(CHARACTER_NAME_KEY, name); // Save the characters name, using the key 'characterName' and setting the value to the provided string value of name. }

SetCharacterName simply takes a parameter of type string, and sets the character name to that. We COULD have this code written in SaveCharacterName also, but in some scenarios we may not want to always SAVE it.

WHY? – Well, when we type the name and end the edit, we may want to set the name in the GameObject, but to avoid the slight performance delay where the games saves, we might wish to delay the save until the end of this gameplay section, i.e. when we’re about to load the next level.

The SaveCharacterName also takes a string parameter, but this time we use it to Save the name to PlayerPrefs, using our KEY we defined in the CONST “CHARACTER_NAME_KEY”. Again, using this CONST is helpful here, to ensure what we SAVE to, is what we LOAD from.

/* * Deletes the characters name. */ public void DeleteCharacterName() { if (PlayerPrefs.HasKey(CHARACTER_NAME_KEY)) { PlayerPrefs.DeleteKey(CHARACTER_NAME_KEY); } else { Debug.Log("No save file to delete!"); } }

If ever you want to simply delete the key reference in PlayerPrefs, use the DeleteKey function, and provide the Key you wish to delete. You can also use PlayerPrefs.DeleteAll() to delete all key and values pairs currently held on PlayerPrefs, but for obvious reasons this should be used with caution.

/* * This function will actually start the process off. It allows us to keep the rest of the code private, and our variables secure. */ public void InputSet() { string name = characterInput.text; SetCharacterName(name); SaveCharacterName(name); } /* * This function actually allows us to grab the information. */ public void InputGet() { characterText.text = GetCharacterName(); }

The InputSet method is a public void, which allows our button to access the method, whereas our other methods are mostly private methods. Setting it as public allows our UI objects to access these methods. We then set a local variable “name” of type string, which simply holds the current text value, of the input we’ve just finished typing to. We then Set the characterName locally, and then Save the characterName to PlayerPrefs.

To get our name, from the UI objects, we also need a public method. This is why we need InputGet.

And that’s it everything, that’s every section of our code, broken down into manageable chunks, to make it easier to understand not only what it’s doing, but why it’s doing it that way.

If we wanted to add in our orb example, we would set up the same methods, except instead of using PlayerPrefs.SetString/GetString, we would use PlayerPrefs.SetInt/GetInt! Try doing this yourself without further reference to see if you fully grasped the concepts.

Which leads us to the next section :

The Pros and Cons of Player Prefs

Pros : +Quick to implement

+Platform independent

+Reliable and not performance intensive Cons : -Limited Data Types

-Not massively scalable

-Not secure for sensitive information

Essentially PlayerPrefs is perfect for saving quick snippets of information, and ensuring they work on all kinds of platforms. It consistently works, and won’t draw any really noticeable amounts of power from your computers hardware to save this information. However, due to the nature of the syntax, and the limitations of the data types that it facilitates, you cannot store massive amounts of information. So you can’t store arrays or information, and as such you have to access them one by one also. Quite simply, this doesn’t make it scalable enough, when you’re working with massive amounts of gameObjects, or complex pieces of information.

The Data Types that PlayerPrefs CAN save :

String – PlayerPrefs.SetString(), PlayerPrefs.GetString()

Int – PlayerPrefs.SetInt(), PlayerPrefs.GetInt()

Float – PlayerPrefs.SetFloat(), PlayerPrefs.GetFloat()

You can also visit the Unity Docs to find a full list of the methods you can use with PlayerPrefs, however, all are covered at some point in this tutorial, except for PlayerPrefs.Save(), which simply saves the player prefs to disk, manually. (by default it does this when you quit the application)

Conclusion

Hopefully you found this tutorial handy and feel it gave a thorough enough explanation to allow you to use PlayerPrefs in your own Games! If you enjoyed this, please get vocal in the comments, like, follow, and of course check out the rest of the content both here, and on Twitter @dalriadaconnor

If you have any more questions also, please feel free to ask questions in the comments, and ask questions on Twitter too! Additionally, if you feel any more information may be helpful, feel free to get in touch there too!

Until next time!

EDIT : The original article wrote about saving and loading boolean values using PlayerPrefs – which is actually incorrect! Thank you to @weirdbeardgdevwho pointed it out! What had happened is that I had written an extension a while ago, and forgotten that it was not actually part of PlayerPrefs code!

If you DID want PlayerPrefs to handle bool values, we’d simply write out own static class, and use that to access boolean values, and simply take advantage of Unity’s PlayerPrefs.SetInt, GetInt functions. Like so:





public static class ExtendedPlayerPrefs{ public void SetBool(string key, bool val){ int result = 0; switch(val){ case true: result = 1; break; case false: result = 0; break; PlayerPrefs.SetInt(key, result); } public bool GetBool(string key){ bool result = false; int p = PlayerPrefs.GetInt(key); switch(p){ case 0: result = false; break; case 1: result = true; break; default: Debug.Warning("Key does not contain a boolean convertible value"); return null; break; } return result; }

With this class written on a script in your code, you can simply set and get boolean values using PlayerPrefs like so:

// To Set Keys and Values ExtendedPlayerPrefs.SetBool("mytest", true); // To Get Values From Your Key ExtendedPlayerPrefs.GetBool("mytest"); // returns true (or false if you set it as such)