Jump to content
  • entries
    44
  • comments
    19
  • views
    2320

Day 32 of 100 Days of VR: Learning about Saving and Loading Data in Unity

Josh Chang

693 views

Hello and welcome back to day 32!

Today is going to be an exciting day. We’re going to work on something that we’ve never seen before in any of the tutorials: Saving and Loading data in Unity!

Specifically, we’re going to save and load our high score from our game in Unity.

From this great Unity video on how to Save and Load data and my own research, I found 3 ways for us to save data:

  1. Using PlayerPrefs
  2. Using Data Serialization
  3. Using a Server

Now with our goals set, let’s get started!

Step 1: Saving with PlayerPrefs

In the first step, we’re going to look at some of the possible ways we can save and load data.

From this great Unity video on how to Save and Load data and my own research, I found 3 ways for us to save data:

Note: for step 1, none of the code will be used in our actual game.

In fact, we’re going to make a separate script just for this.

Step 1.1: Using PlayerPrefs

The first method is PlayerPrefs.

PlayerPrefs is a class that we call that allows us to save and load simple data (think numbers and string) across multiple game sessions.

We can think of PlayerPrefs as a dictionary/table object that takes in a key/value pairing.

For those who haven’t worked with something like this before, what this means is that PlayerPrefs is an object that we can store specific values to a string and when we want to get that value back, we can give it the string.

We’ll see how this works:

  1. In our GameManager game object, click Add Component and create a new TestSaveManager

In the code, we’re just going to store a value in and then print it out to our console.

Here it is:

using UnityEngine;

public class FakeSaveManager : MonoBehaviour
{
    void Start () {
	if (PlayerPrefs.HasKey("FakeScore"))
	{
	    int savedScore = PlayerPrefs.GetInt("FakeScore");
	    print("We have a score from a different session " + savedScore);
	}
	else
	{
	    PlayerPrefs.SetInt("FakeScore", 1337);
	    print("We don't have a score yet, so we're adding one in");
	}
    }
	
}

New Variables Used

None

Walking Through the Code

PlayerPrefs is a static object that we can just access. Here’s what we did:

  1. In Start() the first thing we did was check if we stored a value to our key string: FakeScore.

From here 2 things will happen.

First Run Through

The first time we run the code, we haven’t stored anything yet, so we’ll go to our else statement and set an Int with the value 1337 to our key FakeScore.

We also print in our console notifying us that it’s the first time we did that.

Now if we run the game for the first time, here’s what we’ll see:

playerprefs-starting-out.png

Notice that it says we don’t have a score yet?

Second Run Through

Now after we ran the code for the first time and we added our key/value pair to our PlayerPrefs. If we were to run the code again, we’ll go to the other code path.

In the if statement, we’ll get the value we stored inside our key “FakeScore”, which is 1337.

We’ll print out 1337.

Play our game again and here’s what we get:

playerprefs-second-run.png

See how we have a score now? That means our score persisted from our previous game. Neat!

Step 1.2: Why use PlayerPrefs

Looking at what we’ve done, when do we want to use PlayerPrefs?

The benefit of PlayerPrefs is:

  • Fast and easy to use with no setup required to store primitive variables

The con of PlayerPrefs:

  • If the data we’re storing is important, the user can easily access the data and change it

Why is it insecure you might ask?

Well, it turns out that any data that we’re saving is saved in open space on your computer. In a Windows machine, you can find these values un-encrypted in our registry. Here it is:

regedit.png

Do you see the 2nd item from the top of the list FakeScore and the value is 1337.

Any computer savvy hacker who has knowledge of how Unity works can easily go in and make changes to these values to increase our score.

To summarize: Only use PlayerPrefs to store information that doesn’t really affect the game, such as player settings: brightness, audio sound, special effects, etc.

Do not use it to store things like high scores or sensitive information like your credit card information.

Step 2: Saving with Data Serialization

After looking at PlayerPrefs we have another method of storing data and that is using data serialization with the help of BinaryFormatter and FileStream class.

How this method works, is that we’re:

  1. Taking data (either an object we made serializable, a primitive value, or a JSON)
  2. Convert it to numbers
  3. Storing it somewhere in our device

We’ll discuss the details further down.

Step 2.1: Using Data Serialization

I’ve made some changes to our FakeSaveManager:

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;

public class FakeSaveManager : MonoBehaviour
{
	void Start () {
	    /*if (PlayerPrefs.HasKey("FakeScore"))
	    {
	        int savedScore = PlayerPrefs.GetInt("FakeScore");
	        print("We have a score from a different session " + savedScore);
	    }
	    else
	    {
	        PlayerPrefs.SetInt("FakeScore", 1337);
	        print("We don't have a score yet, so we're adding one in");
	    }*/
        SaveWithSerializer();
        LoadWithSerializer();
    }

    private void SaveWithSerializer()
    {
        BinaryFormatter formatter = new BinaryFormatter();
        print("Save location: " + Application.persistentDataPath);
        FileStream fileStream = File.Create(Application.persistentDataPath + "/save.dat");
        
        formatter.Serialize(fileStream, 1337);
        fileStream.Close();
    }

    private void LoadWithSerializer()
    {
        BinaryFormatter formatter = new BinaryFormatter();
        FileStream fileStream= File.Open(Application.persistentDataPath + "/save.dat", FileMode.Open);

        print("serializer got back: " + formatter.Deserialize(fileStream));
        fileStream.Close();
    }
}

New Variables Used

None

Walking Through the Code

The first thing you might notice is that I commented out the PlayerPrefab code. We don’t need that anymore, we’re just going to focus on the serialization part.

Before we walk through the code, let’s talk about these individual classes that we’re using.

FileStream

We can think of FileStream is a class that allows us to interact with files. In this case, use File.Create() and File.Open() to give us access to these files that we want to access.

Notice how we use something called Application.persistentDataPath when we create and open a file? persistentDataPath is a file location in our computer/phone that we can use to store our game files. Each path is different depending on the OS that the game is running on.

On a windows machine, here’s where the file would be saved to:

serilaizer-path-location.png

Notice how we called our file “save.dat”, that’s just what we call it, the file can be any format we want and it’ll still function the same way.

After we set up our FileStream, we will give it to our BinarySerializer so that it can use it to store our data.

It’s also important to remember that when we’re done using a FileStream, we should always call Close() to prevent a memory leak.

BinaryFormatter

We can think of the BinaryFormatter class as a useful utility that takes in a FileStream and reads/write data into the file.

In our specific example, I put the float 1337 inside, but we can put in classes that we create ourselves.

However, if we were to create our own object, we must make sure we tell Unity to serialize it (by putting [Serialize] on top of the class name).

The two important function we have to know is Serialize() and Deserialize().

  • Serialize is how we change our data into binary and then store them in our File
  • Deserialize is how we read the data back from binary.

If we were to open the file that we saved data into, here’s what we have:

serializer-file-content.png

Now that we understand everything used, let’s walk through the code:

  1. In Start(), we call SaveWithSerializer() which uses a BinaryFormatter and a FileStream to help us store our data, which in this case is just a float value.
  2. We create a new FileStream with the path to where we want to save our data to. We use Application.persistentDataPath to give us a location to store our file that changes depending on what OS is running our game. This is Unity making sure we put our save files in the right location so we can access it back later no matter what platform we’re using.
  3. After we have our FileStream we would use the BinaryFormatter to Serialize our data to the path we specified. After that, make sure to close our FileStream to prevent memory leaks!
  4. After we save, we call LoadWithSerializer() we do a similar operation where we create a BinaryFormatter and a FileStream to the location of the file we previously saved.
  5. With these two objects, we Deserialize, which means we unencrypt our data and put it back into a usable form for us. At this point, we have our data back.

Step 2.2: Why Use Data Serialization?

At this point, you might guess why we might want to use Data Serialization:

  • Our data is encrypted so it’s harder for the players to find it and modify the file.
  • In our example, we only store one variable, but we can actually save a lot more than just that

However, just like the PlayerPrefab, the con is:

  • We know the location of the file, and just because it’s in binary, it doesn’t mean it can’t be reverse engineered!

When should we use Data Serialization?

The answer: almost everything! Data serialization can be used as a database for our equipment, magic spells, and more! We can also use it to store information about our player character.

My only caveat is that if the game you’re creating is multiplayer where you don’t want players to have an unfair advantage, then you DO NOT want to save data about the player locally.

We can store information that the game references where we don’t modify, such as stats of an equipment locally, however information like player inventory is best stored somewhere else.

Where is that somewhere else? Good question, that’s the topic of our next method.

Step 3: Saving Data to A Server

The final and last way for us to store data for our game are to save the data to an external web server which we control and access.

From the external server, we would keep track of the state of the player, for example:

  • What level they are
  • How much money they are
  • What items they have in their inventory

All information that is changeable by the player should be saved externally in a server, where we can do verifications to make sure the player is what they say they are.

Step 3.1: Using a Server

I’m not going to create a server, but rather discuss how we would do it if we wanted to.

The first thing we must do is host a web server online somewhere.

Once the server is up, from our game, ie the client, we would make HTTP network request to our server passing around whatever data our server requires.

A general flow of what we would expect is that:

  • Whenever we’re ready to save our data, we would send the data to our server
  • Whenever we want to load our data, we would make a request to our server for our data.

When sending data over the network, we can’t just send our whole class over, our web server have no idea what anything is.

To solve this problem, we’re going to have to convert our objects into a JSON object and then send it across the network.

I won’t go too deep into the details, but a JSON object is basically a string representation of our object that we can easily convert back and forth.

We would send this string to our server where we would parse it, validate the data, and then save it in the database.

When we’re loading information, the server would send a JSON object back to the game where we would also parse and change the JSON back into something we can use.

Step 3.2 Why use a server?

The benefit of using this approach to store our data is:

  1. Cheating is impossible. Assuming there are no vulnerabilities and we have good data checks, it’ll be very hard for the player to be able to modify their own data and have it saved on our server.
  2. Similar to Data Serialization, we can save more complex data than just primitive variables.

The cons are:

  1. We need a server, which costs money.
  2. There’s more overhead work needed. We need to create our own database, know how to set up a server, and deal with storing multiple players instead of one.

The big question here is: when should we use a server?

The answer: In any game that has multiplayer that we don’t want players to get an unfair advantage against each other. If not, there should be no problem to storing everything locally.

Conclusion

Today, we explored the options that are available to us to save data in a game.

The 3 ways we explored are:

  • PlayerPrefs
  • Data Serialization
  • Sever

Most likely, in a real game, we would use all 3, but the best way for me to summarize when to use each is:

Use PlayerPrefs to store player setting information that doesn’t affect the game itself.

Use Data Serialization to store database information that we will only reference, but not change

Use a Server when we have a multiplayer game where we want to ensure no one can cheat by sending all player data to a server where we can do validation on the authenticity of the data.

For a single player game, however, we can save the data in a serialized file or if it’s simple enough, even in our PlayerPrefs.

Now that we spent Day 32 looking at saving data, it’s finally time for us to start using it on Day 33!

I’ll see you all next time to start putting everything we learned into action!

Source: Day 32

Visit the 100 Days of Unity VR Development main page.

Visit our Homepage



0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
  • Advertisement
  • Blog Entries

  • Similar Content

    • By trapazza
      I'm trying to add some details like grass, rocks, trees, etc. to my little procedurally-generated planet. The meshes for the terrain are created from a spherified cube which is split in chunks (chunked LOD).
      To do this I've wrote a geometry shader that takes a mesh as input and uses its vertex positions as locations where the patches of grass will be placed (as textured quads).
      For an infinite flat world (not spherical) I'd use the terrain mesh as input to the geometry shader, but I've found that this won't work well on a sphere, since the vertex density is not homogeneous across the surface.
      So the main question would be: How to create a point cloud for each terrain chunk whose points were equally distributed across the chunk?
      Note: I've seen some examples where these points are calculated from intersecting a massive rain of totally random perpendicular rays from above... but I found this solution overkill, to say the least.
      Another related question would be: Is there something better/faster than the geometry shader approach, maybe using compute shaders and instancing?
    • By FedGuard
      Hello all,
       
      I would like to start off with thanking you all for this community. Without fora like these to assist people the already hard journey to making an own game would be exponentially more difficult. Next I would like to apologize for the long post, in advance...
      I am contemplating making a game. There, now that's out of the way, maybe some further details might be handy.
      I am not some youngster (no offence) with dreams of breaking into the industry, I am 38, have a full-time job, a wife, kid and dog so I think I am not even considered indie? However I recently found myself with additional time on my hands and decided I would try my hand at making a game.Why? Well mostly because I would like to contribute something, also because I think I have a project worth making (and of course some extra income wouldn't hurt either to be honest). The first thing I realized was, I have absolutely no relevant skill or experience. Hmm; ok, never mind, we can overcome that, right?
      I have spent a few months "researching",meaning looking at YouTube channels, reading articles and fora. Needless to say, I am more confused now than when I started. I also bought some courses (Blender, Unity, C#) and set out to make my ideas more concrete.
      I quickly discovered, I am definitely not an artist... So I decided, though I do plan to continue learning the art side eventually, I would focus on the design and development phase first. The idea being, if it takes me a year or more solely learning stuff and taking courses without actually working on my game, I would become demoralized and the risk of quitting would increase.
      So I thought I would:
      1: Keep following the courses Unity and C# while starting on the actual game development as the courses and my knowledge progress.
      2: Acquire some artwork to help me get a connection with the game and main character, and have something to helm keep me motivated. (I already did some contacting and realized this will not be cheap...). Also try to have the main character model so I can use it to start testing the initial character and game mechanics. For this I have my first concrete question. I already learned that outsourcing this will easily run up in the high hundreds or thousands of dollars... (lowest offer so far being 220 USD) I am therefore playing with the idea of purchasing https://assetstore.unity.com/packages/3d/animations/medieval-animations-mega-pack-12141 with the intention of then have an artist alter and/or add to the animations (it is for a Roman character so some shield animations are not going to work the same way.). This way I could start  with the basic character mechanics. Is this a good idea, waste of money,...? Any suggestions? I then have a related but separate question. Is it a good idea to buy Playmaker (or some other similar software I haven't yet heard of like RPGAIO), and using this for initial build, then changing/adding code as the need arises?
      3.Get a playable initial level ready as a rough demo and then starting to look for artist for level design and character/prop creation.
      ...
       
      I would really appreciate some input from more experienced people, and especially answers to my questions. Of course any advice is extremely welcome.
    • By GameTop
      Dirt Bike Extreme - another game made with Unity. Took about 2 months to complete.
      Take part in extreme motorcycle races across the dangerous and challenging tracks. Dirt Bike Extreme is easy to pick up but hard to master. Race, jump and crash your way and other mad rivals through the amazing tracks as you master the skills and physics of motocross in this high-speed racing adventure. Conquer challenging routes on 23 different runs, discover new bikes and become the best of the best! Over 257K downloads already!
      Windows Version:
      https://www.gametop.com/download-free-games/dirt-bike-extreme/

      Mac Version:
      https://www.macstop.com/games/dirt-bike-extreme/
       

       


    • By Sergio Ronchetti
      Continuing to work on “Eldest Souls” (first article here!), I’ve begun familiarising myself with the workflow between Fmod and Unity, and the integration system. I know much of this will be pretty obvious to most, but I thought I’d share my thoughts as a complete beginner learning the ropes of sound designing. 
      The library of sounds that Fmod provides has been very useful, at least as reference points. I’ve still kept to my ethos of producing the sounds myself as much as possible. Having said that, Fmod gives you 50 free sounds with your download, and I’ve used a wooden crate smash, a drawbridge and electricity sound you can hear in the foley video below.
       
       
      The thing i found most useful was witnessing changes i made in Fmod being realised instantly in Unity. If a volume needed changing, or the timing of one of my effects was off, i can literally switch to Fmod and then back to Unity and immediately see the result of my alterations. It also seems apparent that using middleware such as this (or i've heard Wwise is also equally intuitive) grants the developer, and myself included, a great deal more flexibility and opportunity to edit sounds without going all the way back to a DAW, and bouncing down again. Needless to say, my workflow is so much faster because of it.
      I've also loved the randomised feature of Fmod, whereby any sound can be made to sound slightly different each time it is heard. Taking a footstep recording i made for example, I was able to add further authenticity of uneven footsteps by randomising the pitch and volume of each playback. 
       

       
      I used this technique when creating footsteps for the first major boss in the game called "The Guardian". A big, over-encumbered husk of a monster. I also had fun rummaging through the garage for old tools and metal components for the “Guardian” (the first boss) footsteps. See below!
       
       
      I also created a sword attack for our player, trying to sound different from the generic “woosh” I see in so many video games. I used a very “sharp” and abrasive sound to differentiate him from any enemies.
       
       
      On another note, I recently upgraded my microphone to a Rode NTG2 shotgun, which has been phenomenal. I haven’t had to worry about noise interfering with the clarity of my objects, whereas before with the sm58 I had to be clever with my EQ and noise reduction plugins.
      Important to note again that this still a “cheap” mic in comparison to most other products on the market, and all in all my entire setup is still very simple and affordable which I’m quite proud of. I’ve seen many musicians spend heaps of money on gear they don’t necessarily need. I much prefer being resourceful with less equipment, than to have more than I can understand or remember how to use.
      It’s forced me to understand every aspect and capability of my tools, which I believe is a principal that can be applied to any discipline.
       
      I have more fun little sound effect videos on my Instagram for those interested, where I post regular updates. Thanks for reading! (if you’ve made it this far)
       
      www.sergioronchetti.com
      INSTAGRAM
      fallenflagstudio.com
    • By Sergio Ronchetti
      BASICS IN SOUND DESIGNING FOR VIDEO GAMES
       
      Recently I joined the talented team at Fallen Flag Studio as the composer for their latest release "Eldest Souls" which consequently lead me into a field I have always dreamt of trying - sound design!
      Having no prior experience, I began watching a few online tutorials (if you want to learn from anyone make it Akash Thakkar from "Hyper Light Drifter"... what a guy!) and basically just testing stuff out i found around the house. Luckily my dad has a garage FULL of random crap to use.
      Before i continue, it's important to note that i DO NOT have fancy equipment, meaning anyone can try this. (my equipment is an sm58, focusrite scarlett interface and Logic Pro X plugins... that's it!)
      I started basic with some footsteps, which weren't all too difficult. Then I moved on to projectiles and a spear attack one of the bosses has. Below are a couple super short videos on my resulting attempts.
       
       
      Amazing how great a banjo sounds for that typical "woosh" sound! And if you're wondering, the paper was added to give some texture to the jab.
      I could be finding a lot of these sounds in libraries online (like the built-in ones that come with Fmod and Unity) but I've chosen not to, in order to produce authenticity and hopefully a more unique gameplay experience for players when the final product is put together.
       
      P.S. if you'd like to try the game and hear my hard work we'll be at EGX and several other conventions later this year, soon to be announced! Thanks for reading!
      www.sergioronchetti.com
      fallenflagstudio.com
       
      To those interested, there's an Alpha trailer of the game in question below.
       
       
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!