0

I started doing it a week ago, a simple build game, and now I want a "Save-System". The problem is that whatever I've tried so far, I could not do it. Specifically, I do not know if it would have worked because it would have to stored a 100x100 size ground, plus trees, stones, and constructions. The game randomly generates the world at the start of each run.

Any idea what can I do?

  • Not sure what do you mean by "I do not know if it would have worked". Do you mean you worry it is too much to save? 100x100 tiles, even if you are using 100 bytes per tile, is less than 1 MiB. – Acorn May 20 '18 at 10:42
  • I mean, when I started the game, Unity crashed, and when I try a trick (build the game, and run) the game crashed too.. So I think I need another method, to save more than 10.000 tiles, plus the enverionments. – Levikehh Studios May 21 '18 at 07:15

1 Answers1

0

PlayerPrefs and json serialization will be your friends for a relatively simple save system. But in order to do this, you need to ensure that you are only using the supported PlayerPrefs types: int, float or string. That doesn't provide a lot of wiggle room, so the best way to take advantage of those is to use json, since json is represented as a string. For how to use Unity's built in json serializer read here.

What can you expect with this setup? Well let's take the following setup:

using System;
using UnityEngine;

[Serializable]
public class PlayerStats
{
    public int Health;
    public int Energy;
    public Vector3 Position;

    public static string Serialize(PlayerStats playerStats)
    {
        if (playerStats == null)
            return "";

        return JsonUtility.ToJson(playerStats);
    }

    public static PlayerStats Deserialize(string json)
    {
        if (string.IsNullOrEmpty(json))
            return new PlayerStats();

        return JsonUtility.FromJson<PlayerStats>(json);
    }
}

public static class GameManager
{
    public const string PLAYER_STATS_SAVE_KEY = "PLAYER_STATS";

    public static PlayerStats Player;

    public static void Save()
    {
        string json = PlayerStats.Serialize(Player);
        PlayerPrefs.SetString(PLAYER_STATS_SAVE_KEY, json);
    }

    public static void Load()
    {
        if (!PlayerPrefs.HasKey(PLAYER_STATS_SAVE_KEY))
        {
            Player = new PlayerStats();
        }
        else
        {
            string json = PlayerPrefs.GetString(PLAYER_STATS_SAVE_KEY);
            Player = PlayerStats.Deserialize(json);
        }
    }
}

Here you have 2 classes - PlayerStats and GameManager. PlayerStats will act as the container for the data you want to serialize (and later save and load). So you throw the [Serializable] attribute on it. Add the fields for the data you want to save: Health, Energy and Position. Then create some static methods for Serializing and Deserializing the PlayerStats instance into a Json string. When we run the Serialize() method on the class, we might get a string that looks like this:

{
  "Health": 10,
  "Energy": 10,
  "Position": {
    "x": 1,
    "y": 1,
    "z": 1
  }
}

That means we can save it in PlayerPrefs now since we've gotten all that data converted to a string. That's where the GameManager class comes in. Let's assume you're storing your PlayerStats in a static field in this class. When the player clicks the save button, you would just run GameManager.Save() and it would use the PlayerStats.Serialize() method to get the json of the current PlayerStats. Then using PlayerPrefs, it would store that string at a specific key. The next time you want to load those player stats back, you can just call GameManager.Load() and it will retrieve the saved json from PlayerPrefs, deserialize it into a PlayerStats instance and assign that to your global PlayerStats field.

As for your world generation, I would highly recommend switching to a seeded random generator. This will allow you to generate a random seed which can be saved and reliably used to regenerate the same random data. This can be done with the System.Random(int32) (docs here) class. So instead of saving all of the world data, you just save the seed and use that to regenerate the world.

hanoldaa
  • 616
  • 5
  • 10
  • Thank you! I tried, but when it try to load more then 10.000 gameobject plus components, the Unity crash.. :/ – Levikehh Studios May 21 '18 at 07:18
  • Hah, you might need to put it in a coroutine: generate a max amount per frame -> `yield return null` -> loop through the next pool of objects until if you've loaded them all. You could throw up a loading screen while this coroutine is running (or don't and let the user see everything slowly spawn minecraft style). Also, if this answered your question, would you mind marking it as complete? – hanoldaa May 21 '18 at 19:31