Mastering Save and Load Functionality in Unity 5

By Zdravko Jakupec

Save and Load in Unity

Thanks to Vincent Quarles for kindly helping to peer review this article.

In this tutorial, we’ll finish the implementation of Save and Load functionality in our game. In the previous tutorial on Saving and Loading Player Game Data in Unity, we successfully saved and loaded player-related data such as statistics and inventory, but now we’ll tackle the most difficult part – world objects. The final system should be reminiscent of The Elder Scrolls games – each and every object saved exactly where it was, for indefinite amount of time.


If you need a project to practice on, here’s a version of the project we completed in the last tutorial. It has been upgraded with a pair of in-game interactable objects that spawn items – one potion and one sword. They can be spawned and picked up (despawned), and we need to save and load their state correctly. A finished version of the project (with save system fully implemented) can be found at the bottom of this article.

Download the Project Starting Files

Project GitHub Page
Project ZIP Download


Implementation Theory

We need to break down the system of saving and loading objects before we implement it. First and foremost, we need some sort of Level master object that will spawn and despawn objects. It needs to spawn saved objects in the level (if we are loading the level and not starting anew), despawn picked up objects, notify the objects that they need to save themselves, and manage the lists of objects. Sounds like a lot, so let’s put that into a flowchart:

Flowchart

Basically, the entirety of the logic is saving a list of objects to a hard drive – which, the next time the level is loaded, will be traversed, and all objects from it spawned as we begin playing. Sounds easy, but the devil is in the details: how do we know which objects to save and how do we spawn them back?

Delegates and Events

In the previous article, I mentioned we’ll be using a delegate-event system for notifying the objects that they need to save themselves. Let’s first explain what delegates and events are.

You can read the Official Delegate documentation and the Official Events documentation. But don’t worry: even I don’t understand a lot of the technobabble in official documentation, so I’ll put it in plain English:

Delegate

You can think of a delegate as a function blueprint. It describes what a function is supposed to look like: what its return type is and what arguments it accepts. For example:

public delegate void SaveDelegate(object sender, EventArgs args);

This delegate describes a function that returns nothing (void) and accepts two standard arguments for a .NET/Mono framework: a generic object which represents a sender of the event, and eventual arguments which you can use to pass various data. You don’t really have to worry about this, we can just pass (null, null) as arguments, but they have to be there.

So how does this tie in with events?

Events

You can think of an event as a box of functions. It accepts only functions that match the delegate (a blueprint), and you can put and remove functions from it at runtime however you want.

Then, at any time, you can trigger an event, which means run all the functions that are currently in the box – at once. Consider the following event declaration:

public event SaveDelegate SaveEvent;

This syntax says: declare a public event (anybody can subscribe to it – we’ll get to that later), which accepts functions as described by SaveDelegate delegate (see above), and it’s called SaveEvent.

Subscribe and unsubscribe

Subscribing to an event basically means ‘putting a function in the box’. The syntax is quite simple. Let’s suppose our event is declared in our well-known GlobalObject class and that we have some Potion object class named PotionDroppable that needs to subscribe to an event:

//In PotionDroppable's Start or Awake function:
GlobalObject.Instance.SaveEvent += SaveFunction;

//In PotionDroppable's OnDestroy() function:
GlobalObject.Instance.SaveEvent -= SaveFunction;

//[...]
public void SaveFunction (object sender, EventArgs args)
{
 //Here is code that saves this instance of an object.
}

Let’s explain the syntax here. We first need to have a function that conforms to the described delegate standards. In the object’s script, there is such a function named SaveFunction. We’ll write our own later, but for now let’s just assume that it’s a working function for saving the object to a hard drive so it can be loaded later.

When we have that, we’re simply putting that function in the box at the Start or Awake of the script and removing it when it’s destroyed. (Unsubscribing is quite important: if you try to call a function of a destroyed object you’ll get null reference exceptions at runtime). We do this by accessing the declared Event object, and using an addition operator followed by function name.

Note: We’re not calling a function using brackets or arguments; we’re simply using the function’s name, nothing else.

So let’s explain what all this ultimately does in some example flow of the game.

Logic Flow

Let’s assume that, through the flow of the game, the player’s actions have spawned two swords and two potions in the world (for example, the player opened a chest with loot).

These four objects register their functions in the Save event:

Flowchart demonstrating the Save event

Now let’s assume the player picks up one sword and one potion from the world. As the objects are ‘picked up’, they’re effectively triggering a change in the player’s inventory and then destroying themselves (kind of ruins the magic, I know):

flowchart 3

And then, suppose the player decides to save the game – maybe they really need to answer that phone which rang out three times now (hey, you made a great game):

flowchart 4

Basically, what happens is the functions in the box get triggered one by one, and the game’s not going anywhere until all functions are done. Every object that ‘saves itself’ is basically writing down itself in a list – which, on the next game Load, will be inspected by Level Master object and all objects that are in the list will be Instantiated (spawned). That’s it, really: if you’ve followed the article so far, you’re basically ready to start implementing it right away. Nevertheless, we’re going to some concrete code examples here, and as always, there will be a finished project waiting for you at the end of the article if you wish to see how the whole thing is supposed to look.

Code

Let’s first go over the existing project and familiarize ourselves with what’s inside already.

game screenshot

As you can see, we have these beautifully designed boxes which act as spawners for the two objects we already mentioned. There’s a pair in each of the two scenes. You can immediately see the problem: if you transition the scene or use F5/F9 to Save/Load, the spawned objects will disappear.

The box spawners and the spawned objects themselves use a simple interactable interface mechanic which provides us with the ability to recognize a raycast to those objects, write text on screen, and interact with them using the [E] key.

Not much more is present. Our tasks here are:

  • Make a list of Potion objects
  • Make a list of Sword objects
  • Implement a global Save event
  • Subscribe to the event using a saving function
  • Implement a Level Master object
  • Make Level Master spawn all saved objects if we’re loading a game.

As you can see, this is not exactly as trivial as one might hope such a fundamental function would be. In fact, no existing game engine out there (CryENGINE, UDK, Unreal Engine 4, others) really has a simple Save/Load function implementation ready to go. This is because, as you might imagine, save mechanics are really specific to each game. There’s more to just object classes that usually need saving; it’s world states such as completed/active quests, faction friendliness/hostility, even current weather conditions in some games. It gets quite complex, but with the right foundation of the saving mechanics, it gets easy to simply upgrade it with more functionality.

Object Class Lists

Let’s get started with the easy stuff first – the object lists. Our player’s data is saved and loaded via simple representation of the data in the Serializables class.

code screenshot

In similar fashion, we need some serializable classes which will represent our objects. To write them, we need to know which properties we need to save – for our Player we had a lot of stuff to save. Luckily, for the objects, you’re rarely going to need more than their world position. In our example, we only need to save the Position of the objects and nothing else.

To nicely structure our code, we’ll begin with a simple classes at the end of our Serializables:

[Serializable]
public class SavedDroppablePotion
{
    public float PositionX, PositionY, PositionZ;
}

[Serializable]
public class SavedDroppableSword
{
    public float PositionX, PositionY, PositionZ;
}

You may be wondering why we’re not simply using a base class. The answer is that we could, but you never really know when you need to add or change specific item properties that need saving. And besides, this is far easier for code readability.

By now, you may have noticed I’m using the term Droppable a lot. This is because we need to differentiate between droppable (spawnable) objects, and Placeable objects, which follow different rules of saving and spawning. We’ll get to that later.

Now, unlike Player’s data where we know there’s really only one player at any given time, we can have multiple objects like Potions. We need to make a dynamic list, and denote to which scene does this list belong: we can’t spawn Level2’s objects in Level1. This is simple to do, again in Serializables. Write this below our last class:

[Serializable]
public class SavedDroppableList
{
    public int SceneID;
    public List<SavedDroppablePotion> SavedPotions;
    public List<SavedDroppableSword> SavedSword;

    public SavedDroppableList(int newSceneID)
    {
        this.SceneID = newSceneID;
        this.SavedPotions = new List<SavedDroppablePotion>();
        this.SavedSword = new List<SavedDroppableSword>();
    }
}

The best place to make instances of these lists would be our GlobalControl class:

    public List<SavedDroppableList> SavedLists = new List<SavedDroppableList>();

Our lists are pretty much good to go for now: we’ll access them from a LevelMaster object later when we need to spawn items, and save/load from from Hard Drive from within GlobalControl, like we already do with player data.

Delegate and the Event

Ah, finally. Let’s implement the famous Event stuff.

In GlobalControl:

    public delegate void SaveDelegate(object sender, EventArgs args);
    public static event SaveDelegate SaveEvent;

As you can see, we’re making the event a static reference, so it’s more logical and easier to work with later.

One final note regarding Event implementation: only the class which contains the event declaration can fire an event. Anybody can subscribe to it by accessing GlobalControl.SaveEvent +=..., but only GlobalControl class can fire it using SaveEvent(null, null);. Attempting to use GlobalControl.SaveEvent(null, null); from elsewhere will result in compiler error!

And that’s it for the Event implementation! Let’s subscribe some stuff to it!

Event Subscription

Now that we have our event, our objects need to subscribe to it, or, in other words, start listening to an event and react when it fires.

We need a function that will run when an event fires – for each object. Let’s head over to PotionDroppable script in Pickups folder. Note: Sword doesn’t have its script set up yet; we’ll make it in a moment!

In PotionDroppable, add this:


public void Start()
    {
        GlobalControl.SaveEvent += SaveFunction;
    }

public void OnDestroy()
{
    GlobalControl.SaveEvent -= SaveFunction;
}

public void SaveFunction(object sender, EventArgs args)
{

}

We correctly did the subscribe and unsubscribe to an event. Now the question remains, how to save this object in the list, exactly?

We first need to make sure we have a list of objects initialized for the current scene.

In GlobalControl.cs:

public void InitializeSceneList()
    {
        if (SavedLists == null)
        {
            print("Saved lists was null");
            SavedLists = new List();
        }

        bool found = false;

        //We need to find if we already have a list of saved items for this level:
        for (int i = 0; i < SavedLists.Count; i++)
        {
            if (SavedLists[i].SceneID == SceneManager.GetActiveScene().buildIndex)
            {
                found = true;
                print("Scene was found in saved lists!");
            }
        }

        //If not, we need to create it:
        if (!found)
        {           
            SavedDroppableList newList = new SavedDroppableList(SceneManager.GetActiveScene().buildIndex);
            SavedLists.Add(newList);

            print("Created new list!");
        }
    }

This function needs to be fired once per level. Problem is, our GlobalControl carries through the levels and its Start and Awake functions only fire once. We'll get around that by simply calling this function from our Level Master object which we'll create in a moment.

We are going to need a small helper function to return the current active scene list as well. In GlobalControl.cs:

public SavedDroppableList GetListForScene()
    {
        for (int i = 0; i < SavedLists.Count; i++)
        {
            if (SavedLists[i].SceneID == Application.loadedLevel)
                return SavedLists[i];
        }

        return null;
    }

Now we're sure we always have a list to save our items to. Let's go back to our Potion script:

public void SaveFunction(object sender, EventArgs args)
    {
        SavedDroppablePotion potion = new SavedDroppablePotion();
        potion.PositionX = transform.position.x;
        potion.PositionY = transform.position.y;
        potion.PositionZ = transform.position.z;

GlobalControl.Instance.GetListForScene().SavedPotions.Add(potion);
    }

This is where all our syntactic sugar coating really shines. This is very readable, easy to understand and easy to change for your own needs when you need it! In short, we create a new ‘potion’ representation, and save it in the actual list.

Creating a Level Master Object

First, a small bit of preparation. Within our existing project, we have a global variable that tells us if the scene is being loaded. But we don’t have such variable to tell us if the scene is being transitioned by using the door. We expect for all the dropped objects to still be there when we return to the previous room, even if we didn’t save/load our game anywhere in between.

To do that, we need to make small change to Global Control:

public bool IsSceneBeingTransitioned = false;

In TransitionScript:

public void Interact()
    {
        //Assign the transition target location.
        GlobalControl.Instance.TransitionTarget.position = TargetPlayerLocation.position;

        //NEW:
        GlobalControl.Instance.IsSceneBeingTransitioned = true;
        GlobalControl.Instance.FireSaveEvent();
        
        Application.LoadLevel(TargetedSceneIndex);
    }

We’re ready to make a LevelMaster object that will work normally.

Now we only need to read the lists and spawn the objects from them when we’re loading a game. This is what the Level Master object will do. Let’s create a new Script and call it LevelMaster:

public class LevelMaster : MonoBehaviour
{

    public GameObject PotionPrefab;
    public GameObject SwordPrefab;
    
    void Start ()
    {
        GlobalControl.Instance.InitializeSceneList();

        if (GlobalControl.Instance.IsSceneBeingLoaded || GlobalControl.Instance.IsSceneBeingTransitioned)
        {
            SavedDroppableList localList = GlobalControl.Instance.GetListForScene();

            if (localList != null)
            {
                print("Saved potions count: " + localList.SavedPotions.Count);

                for (int i = 0; i < localList.SavedPotions.Count; i++)
                {
                    GameObject spawnedPotion = (GameObject)Instantiate(PotionPrefab);
                    spawnedPotion.transform.position = new Vector3(localList.SavedPotions[i].PositionX,
                                                                    localList.SavedPotions[i].PositionY,
                                                                    localList.SavedPotions[i].PositionZ);
                }

            }
            else
                print("Local List was null!");
        }
    }
    
}

That’s a lot of code, so let’s break it down.

The code runs only at the start, which we use to initialize the saved lists in GlobalControl if needed. Then, we ask the GlobalControl if we’re loading or transitioning a scene. If we’re starting the scene anew (like New Game or such), it doesn’t matter – we spawn no objects.

If we are loading a scene, we need to fetch our local copy of the list of saved objects (just to save a bit of performance on repeated accessing of GlobalControl, and to make syntax more readable).

Next, we simply traverse the list and spawn all potion objects inside. The exact syntax for spawning is basically one of the Instantiate method overloads. We must cast the result of the Instantiate method into GameObject (for some reason, the default return type is simple Object) so that we can access its transform, and change its position.

This is where the object is spawned: if you need to change any other values at spawn-time, this is the place to do it.

We need to put our level master in each scene and assign the valid Prefabs to it:

Inspector view

Now we’re only missing one crucial piece: we need to actually fire the event, serialize the Lists down to the hard drive and read from them. We’ll simply do that in our existing Save and Load functions in GlobalControl:

 public void FireSaveEvent()
    {
        GetListForScene().SavedPotions = new List<SavedDroppablePotion>();
        GetListForScene().SavedSword = new List<SavedDroppableSword>();
        //If we have any functions in the event:
        if (SaveEvent != null)
            SaveEvent(null, null);
    }

    public void SaveData()
    {
        if (!Directory.Exists("Saves"))
            Directory.CreateDirectory("Saves");

        FireSaveEvent();  

        BinaryFormatter formatter = new BinaryFormatter();
        FileStream saveFile = File.Create("Saves/save.binary");
        FileStream SaveObjects = File.Create("saves/saveObjects.binary");

        LocalCopyOfData = PlayerState.Instance.localPlayerData;

        formatter.Serialize(saveFile, LocalCopyOfData);
        formatter.Serialize(SaveObjects, SavedLists);

        saveFile.Close();
        SaveObjects.Close();

        print("Saved!");
    }

    public void LoadData()
    {
        BinaryFormatter formatter = new BinaryFormatter();
        FileStream saveFile = File.Open("Saves/save.binary", FileMode.Open);
        FileStream saveObjects = File.Open("Saves/saveObjects.binary", FileMode.Open);

        LocalCopyOfData = (PlayerStatistics)formatter.Deserialize(saveFile);
        SavedLists = (List<SavedDroppableList>)formatter.Deserialize(saveObjects);
        
        saveFile.Close();
        saveObjects.Close();

        print("Loaded");
    }

This also appears to be a lot of code, but the majority of that was already there. (If you followed my previous tutorial, you’ll recognize the binary serialization commands; the only new thing here is the FireSaveEvent function, and one additional file that saves our lists. That’s it!

Initial Testing

If you run the project now, the potion objects will be correctly saved and loaded each time do you hit F5 and F9, or walk through the door (and any combination of such).

However, there’s one more problem to solve: we’re not saving the swords.

This is simply to demonstrate how to add new savable objects to your project once you have similar foundations built.

Expanding the System

So let’s say you already have a new object-spawning system in place – like we already do with the sword objects. They are currently not interactable much (beyond basic physics), so we need to write a script similar to the Potion one which will enable us to ‘pick up’ a sword and make it save correctly.

The prefab of the sword that’s currently being spawned can be found in the Assets > Prefabs folder.

Let’s make it work. Go to Assets > Scripts > Pickups and there you’ll see PotionDroppable script. Next to it, create a new SwordDroppable script:

public class SwordDroppable : MonoBehaviour, IInteractable
{
    public void Start()
    {
        GlobalControl.SaveEvent += SaveFunction;
    }

    public void OnDestroy()
    {
        GlobalControl.SaveEvent -= SaveFunction;
    }

    public void SaveFunction(object sender, EventArgs args)
    {
        SavedDroppableSword sword = new SavedDroppableSword();
        sword.PositionX = transform.position.x;
        sword.PositionY = transform.position.y;
        sword.PositionZ = transform.position.z;

GlobalControl.Instance.GetListForScene().SavedSword.Add(sword);

    }
    public void Interact()
    {
        Destroy(gameObject);
    }
    public void LookAt()
    {
        HUDScript.AimedObjectString = "Pick up: Sword";
    }
}

Do not forget the ‘Interactable’ interface implementation. It’s very important: without it your sword will not be recognized by the camera raycast and will remain uninteractable. Also, double check that the Sword prefab belongs to Items layer. Otherwise, it will again be ignored by the raycast. Now add this script to the Sword prefab’s first child (which actually has the Mesh renderer and other components):

Sword droppable

Now, we need to spawn them. In Level Master, under our for loop that spawns the Potions:

for (int i = 0; i < localList.SavedSword.Count; i++)
                {
                    GameObject spawnedSword = (GameObject)Instantiate(SwordPrefab);
                    spawnedSword.transform.position = new Vector3(localList.SavedSword[i].PositionX,
                                                                    localList.SavedSword[i].PositionY,
                                                                    localList.SavedSword[i].PositionZ);
                }

… and that’s it. Whenever you need a new item type saved:

  • add in Serializables class
  • create script for item that subscribes to Save event
  • add Instantiate logic in Level Master.

Conclusion

For now, the system is quite crude: there are multiple save files on the hard drive, the object’s rotation isn’t saved (swords, player, etc.), and logic for positioning a player during scene transitions (but not loading) is a bit quirky.

These are all now minor problems to solve once the solid system is in place, and I invite you to try to tinker around with this tutorial and finished project to see if you can improve the system.

But even as it is, it’s already quite a reliable and solid method for doing Save/Load mechanics in your game – however much it may differ from these example projects.


As promised, here is the finished project, should you need it for reference, or because you got stuck somewhere. The save system is implemented as per this tutorial’s instructions and with same naming scheme.

Download the Finished Project:

Project GitHub Page
Project ZIP Download


  • heckubiss

    Thanks you very much for this article. It simplifies delegates and events which I have been struggling with. One question: Is it really necessary to have a SwordDroppable.cs and a SavedDroppableSword Class in Serializables.cs? cant I just have a sword class that also includes the methods from swordDroppable?

  • Denis Garifullin

    Around the web I found only one true way to save gameobjects. Thank you very much!

  • Denis Garifullin

    Project have broken links to scripts and prefabs. please put the package

    • Eudaimonium

      You’re right, this is weird, it shouldn’t be happening, the project settings are correct for versioning control, yet I still lost links in the editor. (and I know I double checked – you can even see correct settings in Unity…)

      I will export the package for you momentarily when I find this project on my drive.

    • Eudaimonium

      New links are up, now it should be working.

      Thanks for the note!

  • Tubsiwub

    This was very fun to read, and incredibly helpful with how it was explained. I applaud you for the effort.

    • Eudaimonium

      Thank you very much! I am happy if you learned something new :)

  • Dream

    I have a question. I have an RPG that I am creating and I was wondering how you would save an NPC’s location who is able to walk around freely and that they are in a different scene than yours. Would it be better to use multiple scenes for a top down RPG game like Pokemon, or would it be better to use 1 huge scene, or 2-3 huge scenes?

    • Eudaimonium

      That shouldn’t be too tough, just make a serializable class that contains, say, NPC Prefab ID (so you can instantiate it later perhaps, or prefab Resource name), Name, Position, next destination, dialogue exhausted IDs etc. Use simple data types – you can’t serialize Transforms or GameObjects or Components this way.

      Then, simply make a List of those classes in whatever you’re serializing, and write it down to disk.

      At level load, check if scene is loaded, if so initialize all NPCs from saved list. Quite similar to how potions and swords are saved here – they only have their basic info saved but this can be extended with anything you need. It just needs a bit of “programming creativity”.

      Pokemon-like “levels” should be one scene per level – with scene transitions at doors and edges etc. Would make it simpler to start developing/prototyping I think. But it really depends on your particular game design and all. You can always try doing both ways, see what works.

  • androidmanmachine

    Hello
    I am trying to open the project folder from github with Unity 5.3.5f1 – and all the scripts /shaders etc..and stuff are all mashed up…
    Is it possible to have a working version of the example file?

    Thanks,
    AMM

    • Eudaimonium

      To the best of my knowledge the links were fixed a while back, it should work.

      Make sure to visit the Github page through the link, and download ZIP of head revision there (instead of using direct ZIP link from here) just to be 100% sure.

  • lloyd

    Hi, thanks so much for that solid saving/loading approach! Very well thought through and described!
    I was wondering how “placeables” are processed – you mentioned they will follow a different routine than droppables?
    Thanks,
    lloyd

    • Eudaimonium

      Probably should’ve expanded on that as well.

      Basically, the difference between placeables and droppables is that droppables will get spawned into the level by some loading process, your own script.

      Placeables already start with the scene (since you’ve put them there in the Editor), and when picked up, should be noted as “removed” somewhere in your infrastructure.

      Basically the flow is:
      – Spawn the entire scene. If we are loading a save game:
      – Remove picked up placeables
      – Spawn any saved droppables
      – Begin play

      • lloyd

        Ah, i see! Thank you very much!

  • DongHun Lee

    Hi.
    So this solution can also save entire scene while playing game?

    • Eudaimonium

      No, this solution is specifically aimed at saving specific serializable objects, in order to save large amounts of disk space (save file size) and saving/loading times. Serializing an entire scene directly is a very bad idea.

      • DongHun Lee

        Then, are there no other solution that can save entire scene? (workable at unity 5.5 newest version)

        • Eudaimonium

          No, to the best of my knowledge, though I cannot understand when would you want to save an entire scene (as opposed to just saving the _changes_ made to it).

          • DongHun Lee

            I am making tycoon simulation game, so there is not much moving objects. I just want easy save&load feature.

            So if solution is not saving entire scene, I should save specific scripts and after load, I should apply its data to UI and others. (progrssing like update or coroutine).

            But there are none that can save entire scene… (actually one existed but not work at current unity version)

            So, next step is just find out what is good solution that can easily save&load specific objects, custom own classes. And there are plenty of these exist at asset store.

            What will you recommend from those? Thanks.

          • Eudaimonium

            Tycoon-alike games usually have a grid map structure. Saving a “representation” 2d grid of your map should work well. Simply instantiate the needed objects according to the representations saved.

  • BeReady3

    Hey first of all thanks for great tutorial! There is no other detailed tutorial – with finished example project- about saving objects on the entire internet! Thanks for that. I am developing an upgrade system. Is this method more reliable, faster and mobile-friendly than simply saving setActive states of objects?

    • Eudaimonium

      Hi, thanks for your kind words! Though I do believe I saw a few alternative approaches around the internet, but nevertheless I am glad you found it useful.

      I’m afraid I do not understand the question – what do you mean by simply saving active states?

      • BeReady3

        I have an object which I can attach a weapon to it. I make a list of weapon objects and all weapon object are set to be inactive. That list is child of the main object. When I buy first weapon, first weapon becomes active and also a save function saves statements of all weapon objects’ statements. When I upgrade the second weapon, first weapon goes inactive and second weapon is now my current weapon. So the save function now saves the second weapon. I hope you get my point now. I dont even know it is possible to save and load those statements in game.

        • Eudaimonium

          Ah now I understand. Well you basically want to save the entire List of your objects/weapons. Their entire state should be serialized, whether they’re active or not.

          But, a much better solution would be to have some sort of “representation” list. This is the list that gets saved. At Save time, you create this list from your actual weapons’ list and only save the needed info. For example, you can only save a list of booleans if the weapon is active or not.

          Then, at load time, you write code which re-creates your weapon list, from your representation list.

          • BeReady3

            Good to hear that there is way to do that, thanks! Now I am really confused about which way to create my save system. Would you suggest me to use that way or just I should stick to the topic and save objects to memory and load them back? It looks like it is much easier to save booleans of the existing weapons. But that gives me the same question as I asked before. Is this way reliable, faster and mobile-friendly? Also another question how can I delete the saved objects? I try to destroy them ingame and save the game but it loads all the objects (By the way I have a similar problem with your example project too. I spawn potions and swords. I pick up some of them and save the game. When I load the saved game, all picked up swords are still there, but picked up potions are destroyed and they are not there.)

          • Eudaimonium

            Well, you have a bit of a specific scenario, I suggest you play around with the techniques mentioned in the article, and when you’re comfortable using them, implement them in your game – or modify them to suit your needs.

            If you started with the project Starting files, yes they need to be completed using the article as a guide. There’s a download after the article for finished system.

          • BeReady3

            Ok thank you for the helpful answers! This is the first time I am asking for the help on the internet! :) I am using the finished project files by the way. Maybe I changed something while I was looking around but I downloaded the finished project and tried that again and still have the same problem with swords.

  • Atalanthus

    Hey,
    First this is a really good tutorial. I used it for my game and optimized it a bit. Everything works fine.
    But now my question: How could I save enemies or npcs when I want that they’re instantly placed on the scene? (in the editor)
    Currently I saved my enemys in a list just like the potions or swords in this tutorial. But the problem is of course that when I place this enemys in the editor, Unity creates everytime I load this scene a new enemy and load the saved ones. So every enemy gets duplicated.
    I solved this problem with a enemySpawner script that checks for a bool in an DontDestroyOnLoad() object. Everytime I start a new game this bool gets set to true and the enemySpawner script spawns the enemys. But this means instead of placing the enemy objects in the editor I have to set all enemy values I need like the position in this script and this is pretty laborious.
    The other thing would be to make the enemy saving just like the players. I think then I could place them in the editor. But this would mean I have to make for every enemy an own serializable class. And this would be even more laborious.

    So is there another way to solve this? Please let me know and sorry if my englisch isn’t the best.
    Thanks!

    • Eudaimonium

      Hi, thanks a lot for the kind words.

      Indeed, the stuff placed via editor is bit trickier. My approach to solve this was to differentiate between “Placable” and “Droppable”. Droppable is something that does not exist when game starts. That’s appropriate for the loading system of my tutorial.

      Placable, on the other hand, is like an opposite. “Droppable” need to remember it has been spawned, and when scene gets loaded, it will spawn. Placable needs to remember it has been destroyed (picked up, killed, whatever), and when scene gets loaded, it will remove itself. It does not write itself to the same list as Droppables.

      I keep a seperate list for Placables and Droppables. Placables get a unique ID assigned to them (easily obtainable by using, say sqrMagnitude of the item’s location), when they get destroyed they will write this ID to the list of destroyed Placables. Next time the level gets loaded, they obtain their ID, and ask if this ID is already remembered as “destroyed”. If so, they despawn instantly, at scene Start.

      I hope this clears it up a bit. BTW everything in your post was written correctly except “englisch” :D

      • Atalanthus

        Ah ok thats really smart. Thank you! I will try this.
        Will you do another tutorial for this Placables? Because they help really much. :)

        • Eudaimonium

          Maybe, but I am not certain. What little free time I have is spent working on my game (and playing other games, of course) :D

      • Atalanthus

        Why the ID? Couldn’t you just make a new destroyObjects event and when the placable gets destroied it adds a Destroy(gameObject) method to this event.
        This would be similar to the droppable lists. The destroy event gets called within the ObjectLoader script.

        • Eudaimonium

          What would you put in the Destroyed list? You can’t put entire game object, since they’re not serializable (even if they were, the object reference would be different the next time the game runs so it would no longer match to the written reference in the list).

          You have to remember “what” was destroyed somehow, similar to how you remember what was spawned. There’s a million ways to solve this, to be honest, and I’m trying to go for the one that’s easy to explain.

      • Atalanthus

        I think I have one more question if you don’t mind.
        I have it now and it works fine. It’s far away from being perfect but for now I’m just so happy it works.
        My last problem is that when I load my scene and I transition the scene (like I open the map) and then go back to scene the enemy’s get doubled. That’s because I still save the enemy’s with the save event (because of course the enemy’s have to stay on their position and stats) and then the enemys get spawned inside the objectLoader and also the editor enemy’s spawn too.

        I don’t know how I could solve that now but maybe (or probably) I just didn’t understand this placeable thing right.

        • Eudaimonium

          The enemy should not be saved with a save event. They get spawned by default. You only need to remember that you destroyed them (so that they do not spawn next time).

          Now, if you need to remember their saved stats and changed positions and such, that’s a more difficult problem to solve and outside the scope of this tutorial. One way I can think off right now, is to first check if the scene is being loaded (have we visited it before?). If so, destroy all enemies immediately. THEN after this, spawn all enemies that have been saved with save event. It’s a bit of a dirty hack-fix solution… but it should work.

          • Atalanthus

            Thank you. Now it’s working. I still have the enemys in the droppable list and handle them just like a droppable item but I have a bool (spawnNewEnemysInMainScene) in my Don’tDestroyOnLoad() object. When I start a new Game this bool gets set to true and in my Start() method in GameInputManager object which gets destroyed when I load another scene I check the value of this bool. If it is false it gets all placed Enemys (Tag: Enemy) and destroys them. If it’s true it just sets the bool to false and all placed enemys get spawned. When I load the saved Enemys in the ObjectLoaderScript (I instantiate the enemy and set the right values) I change also the enemys tag so it doesn’t get destroyed. (Just explaining this so extensively for others who might need it)

            So now I think I have a great save and load functionality for my game. At this point I have to thank you again for you support on my problem and good luck with your game! :D

  • kevin o’brien

    I have local save states working but it seems when I upload a build to steam it erases player data. arnt persistant data paths read only, therefore it shouldnt overwrite the data?

Get the latest in Front-end, once a week, for free.