• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
65
Question by reboot2009 · Dec 01, 2009 at 04:37 AM · serializationsaveloadfile-io

How to script a Save/Load game option

I would like to be able to save and load a players progress to a players hard disk.

as an example if i have a player that collects 3 gems then a door will open automatically when the 3rd gem is collected. so id like to be able to save the location of the player (in the world or at a save location spot) as well as save the information that the crystals have been collected (i assume each crystal would have a unique name such as crystal_A crystal_B etc...so that when the player loads the game all the crystals won't be loaded again just the ones that have not been collected. )

I would like this system to work as a stand alone game (not a web browser run game) is it possible? does anyone know how?

OH and the reason for the hard disk save is so that if the player has to wipe the pc clean the player should be able to fine the directory where the file is saved and back up his save game. (this has saved me from loosing all my hard work on games i've played in the past when antivirus failed to protect my pc)

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

17 Replies

· Add your reply
  • Sort: 
avatar image
92
Best Answer

Answer by TowerOfBricks · Dec 01, 2009 at 07:15 AM

There are loads of solutions to that. The most used one is called PlayerPrefs and some documentation about that can be found in the docs. That approach does not save the data to a file which you can place anywhere you want though so that solution might be out of the question.

The second solution is called XML serialization and can automatically generate an XML file from a class, it can also put together the class from an XML class so you won't need to worry about writing your own parser. On the wiki there is a full example script using XML serialization.

The third option is using mono's serialization class, it works much like the XML serializer but requires a bit more work but is a lot more stable in return. I don't have any code here so I don't remember where the documentation is, a search on the forums always yields good results though.

The fourth option is to write a parser of your own, I have tried this and it is quite hard, especially when dealing with floats (vectors too). Documentation about this can be found when searching for XML text writer or StringWriter.

Hope this gives you some ideas! If you decide to use one option I can explain more about that then.

[Edit] Well I though a bit about the XML serialization, and actually I don't think it will be very good for your game to store it that way. The XML will look something like this

<Player>
  <Score score=245>
  <Life life=85>
</Player>

Which means the player will be able to open the XML file in a text editor and change whatever he/she wants, and that isn't so good, is it?

Stable wasn't the right word I think, limited would suite better, for example the XML serializer can't save Hashtables or any special stuff, neither can it save classes other than primitive types (I can't anyway, I have heard that it should work).

So I think the "ordinary" serializer would work better for you.

If you still want to use the XML serializer you can take a look here

The Serializer works like this:

You create a holder class for everything you want to save and then you mark it with the Serializable attribute:

[Serializable ()] public class SaveData : ISerializable { public bool foundGem1 = false; public float score = 42; public int levelReached = 3;

 public SaveData () {
 }

}

Then you have to define functions for how the class should be loaded and how it should be saved, these should be put inside the class.

public SaveData (SerializationInfo info, StreamingContext ctxt) { //Get the values from info and assign them to the appropriate properties foundGem1 = (bool)info.GetValue("foundGem1", typeof(bool)); score = (float)info.GetValue("score", typeof(float));

     levelReached = (int)info.GetValue("levelReached", typeof(int));
 }

 //Serialization function.

 public void GetObjectData (SerializationInfo info, StreamingContext ctxt)
 {

     info.AddValue("foundGem1", (foundGem1));
     info.AddValue("score", score);
     info.AddValue("levelReached", levelReached);
 }

The only thing left now is the save and load functions in your script.

public void Save () {

 SaveData data = new SaveData ();

 Stream stream = File.Open("MySavedGame.game", FileMode.Create);
 BinaryFormatter bformatter = new BinaryFormatter();
     bformatter.Binder = new VersionDeserializationBinder(); 
 Debug.Log ("Writing Information");
 bformatter.Serialize(stream, data);
 stream.Close();

}

public void Load () {

 SaveData data = new SaveData ();
 Stream stream = File.Open("MySavedGame.gamed", FileMode.Open);
 BinaryFormatter bformatter = new BinaryFormatter();
 bformatter.Binder = new VersionDeserializationBinder(); 
 Debug.Log ("Reading Data");
 data = (SaveData)bformatter.Deserialize(stream);
 stream.Close();

}

Oh, just one thing more, you need to define a VersionDeserializationBinder class, otherwise you can't load the game when you open it later, something about Unity generates a new key of some sort for the binary formatter, search for "Serialization" on the forum and you can find a post about that.

public sealed class VersionDeserializationBinder : SerializationBinder { public override Type BindToType( string assemblyName, string typeName ) { if ( !string.IsNullOrEmpty( assemblyName ) && !string.IsNullOrEmpty( typeName ) ) { Type typeToDeserialize = null;

         assemblyName = Assembly.GetExecutingAssembly().FullName; 

         // The following line of code returns the type. 
         typeToDeserialize = Type.GetType( String.Format( "{0}, {1}", typeName, assemblyName ) ); 

         return typeToDeserialize; 
     } 

     return null; 
 } 

}

You will need to use these namespaces to get it working:

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

using System; using System.Runtime.Serialization; using System.Reflection;

Done, at last :D

Comment
Add comment · Show 13 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image reboot2009 · Dec 01, 2009 at 05:42 PM 0
Share

The X$$anonymous$$L serialization sounds interesting. What makes it less stable than a mono serialization?

If you could tell me more about X$$anonymous$$L that would be great! I'm sure I could work around any limitations it has.

Thank you so much for your help!

avatar image TowerOfBricks · Dec 07, 2009 at 05:08 PM 0
Share

Updated my post above!

avatar image SoundGuy32 · Jun 16, 2010 at 06:38 AM 0
Share

How can i make something like this work on unity iphone basic?

avatar image SoundGuy32 · Jun 17, 2010 at 05:49 AM 0
Share

also - when i'm trying to implement the VersionDeserializationBinder function it shouts: error CS0246: The type or namespace name `Type' could not be found. Are you missing a using directive or an assembly reference? what am i doing wrong?

avatar image TowerOfBricks · Jun 18, 2010 at 09:40 AM 0
Share

You should have using System; at the top of your C# script. Or you could put System. before the word Type so it says System.Type. I haven't tried this on the iPhone, but I have heard that there is a lightweight X$$anonymous$$L library available somewhere which you might be able to use.

Show more comments
avatar image
26
Wiki

Answer by CJCurrie · Apr 05, 2011 at 05:35 PM

I took TowerOfBricks's code for data serialization and put it together into a single script, complete with thorough commenting. Might be good for people looking to understand the save/load process a little better.

 using UnityEngine;    // For Debug.Log, etc.
 
 using System.Text;
 using System.IO;
 using System.Runtime.Serialization.Formatters.Binary;
 
 using System;
 using System.Runtime.Serialization;
 using System.Reflection;
 
 // === This is the info container class ===
 [Serializable ()]
 public class SaveData : ISerializable {
 
   // === Values ===
   // Edit these during gameplay
   public bool foundGem1 = false;
   public float score = 42;
   public int levelReached = 3;
   // === /Values ===
 
   // The default constructor. Included for when we call it during Save() and Load()
   public SaveData () {}
 
   // This constructor is called automatically by the parent class, ISerializable
   // We get to custom-implement the serialization process here
   public SaveData (SerializationInfo info, StreamingContext ctxt)
   {
     // Get the values from info and assign them to the appropriate properties. Make sure to cast each variable.
     // Do this for each var defined in the Values section above
     foundGem1 = (bool)info.GetValue("foundGem1", typeof(bool));
     score = (float)info.GetValue("score", typeof(float));
 
     levelReached = (int)info.GetValue("levelReached", typeof(int));
   }
 
   // Required by the ISerializable class to be properly serialized. This is called automatically
   public void GetObjectData (SerializationInfo info, StreamingContext ctxt)
   {
     // Repeat this for each var defined in the Values section
     info.AddValue("foundGem1", (foundGem1));
     info.AddValue("score", score);
     info.AddValue("levelReached", levelReached);
   }
 }
 
 // === This is the class that will be accessed from scripts ===
 public class SaveLoad {
 
   public static string currentFilePath = "SaveData.cjc";    // Edit this for different save files
 
   // Call this to write data
   public static void Save ()  // Overloaded
   {
     Save (currentFilePath);
   }
   public static void Save (string filePath)
   {
     SaveData data = new SaveData ();
 
     Stream stream = File.Open(filePath, FileMode.Create);
     BinaryFormatter bformatter = new BinaryFormatter();
     bformatter.Binder = new VersionDeserializationBinder(); 
     bformatter.Serialize(stream, data);
     stream.Close();
   }
 
   // Call this to load from a file into "data"
   public static void Load ()  { Load(currentFilePath);  }   // Overloaded
   public static void Load (string filePath) 
   {
     SaveData data = new SaveData ();
     Stream stream = File.Open(filePath, FileMode.Open);
     BinaryFormatter bformatter = new BinaryFormatter();
     bformatter.Binder = new VersionDeserializationBinder(); 
     data = (SaveData)bformatter.Deserialize(stream);
     stream.Close();
 
     // Now use "data" to access your Values
   }
 
 }
 
 // === This is required to guarantee a fixed serialization assembly name, which Unity likes to randomize on each compile
 // Do not change this
 public sealed class VersionDeserializationBinder : SerializationBinder 
 { 
     public override Type BindToType( string assemblyName, string typeName )
     { 
         if ( !string.IsNullOrEmpty( assemblyName ) && !string.IsNullOrEmpty( typeName ) ) 
         { 
             Type typeToDeserialize = null; 
 
             assemblyName = Assembly.GetExecutingAssembly().FullName; 
 
             // The following line of code returns the type. 
             typeToDeserialize = Type.GetType( String.Format( "{0}, {1}", typeName, assemblyName ) ); 
 
             return typeToDeserialize; 
         } 
 
         return null; 
     } 
 }

             
Comment
Add comment · Show 10 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Kith · Jul 30, 2011 at 07:16 PM 0
Share

Hey, I know this is an old post, but what is the file type cjc?

avatar image fffMalzbier · Aug 02, 2011 at 09:12 AM 0
Share

Thx the script is working fine but i have one BIG problem. I cant edit the variables like: public bool foundGem1 = false; public float score = 42; public int levelReached = 3;

from another class. and in addition i cant Access no other variable form other scripts from within the SaveData class.

@$$anonymous$$ith: .cjc is like .xml or .abc its your decision how to name the file the inners are the same and working the same. Its useful to show the user DO NOT EDIT THIS when you use not a common type X$$anonymous$$L or TXT.

avatar image Keavon · Nov 02, 2011 at 06:49 AM 2
Share

I will point out that cjc is an abrieviation of his username, CJCurrie.

avatar image Bashosha · May 31, 2012 at 11:23 AM 0
Share

@Colin Currie should we make the class "SaveData" singleton if I am gonna use it in multiple scripts?

avatar image Bunny83 · May 31, 2012 at 11:38 AM 0
Share

@Bashosha: Well that can get you in trouble. A singleton usually have to be able to create it's instance automatically. Since you want it to be deserialized from somewhere it won't work.

Howevery, it is possible when you create / deserialize the singleton manually at start.

Show more comments
avatar image
5

Answer by Ehren · Dec 01, 2009 at 05:03 PM

Another option is to purchase a third-party save/restore tool, such as EZ Game Saver from Above & Beyond Software.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image reboot2009 · Dec 01, 2009 at 06:05 PM 0
Share

that is an excellent suggestion! unfortunately it is currently out of my price range.

avatar image Statement · Feb 19, 2010 at 09:46 AM 5
Share

Remember that it is always good to evaluate existing solutions as coding your own may cost you more in time and maintainance than to pay the price up front (given it works as expected and fulfill your needs).

avatar image
3

Answer by Thoben · Oct 13, 2010 at 04:02 PM

@The Stone: Big THX for sharing, this serialization works perfectly.

I've tested it on the iPad with Unity 3. You can use it the exact way, except you have to choose carefully where to save and load the file, because you only have restricted access to the device's folders.

For me the Application's "Documents" folder worked very well:

Stream stream = File.Create(Application.dataPath + "/../../Documents/" + "MySavedGame.game");

Use the same path for loading.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
2

Answer by Kevin Tweedy · Jul 26, 2010 at 06:39 AM

Maybe another option would be to serialize to XML then zip up or encrypt the XML in some way and save it out to disk.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image shadowpuppet · Dec 11, 2017 at 05:58 AM 0
Share

I'm fine with using player prefs. Personally if someone wants to hack into it to cheat let them - at least for my games because there is no global leaderboard or cash awards and what ids the point of playing if take away the challenge by giving yourself God$$anonymous$$ode or unlimited ammo or extra cash points. I think people that into game do so for the challenge and if you take away the challenge by storing game info in a file a 5 year old could alter it kind of di$$anonymous$$ishes the feat of having hacked as well as wrecking gameplay

  • 1
  • 2
  • 3
  • 4
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

27 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Serialized data not getting saved in iPhone 1 Answer

Which types are actually serializable? Is the documentation incorrect or am I? 3 Answers

Save and Load from XML U3 Collections Problem 1 Answer

Save and load serialization problem 0 Answers

Error serializing a class to save / load 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges