Infinite Save Scripting

Scripting an infinite save system.

Step 1: Create a Script

Create a script or multiple scripts that will handle all save menu functionality.

For this example, we will create a single script called InfiniteSavesExample.cs.

Start the script by adding the member variables that can be set from the inspector.

public class InfiniteSavesExample : MonoBehaviour
{
    [SerializeField]
    private Button saveSlotPrefab;
    
    [SerializeField]
    private Button saveSlotCreator;
    
    [SerializeField]
    private Transform content;
    
    [SerializeField]
    private Text timeElapsedText;
    
    [SerializeField]
    private Toggle modeToggle;
}

Remember to add a GameObject to the scene and add this script to it. At this point, we should have everything to populate the inspector properties.

Properties

Save Slot Prefab: the save slot button prefab.

Save Slot Creator: the button that will create a new save.

Content: the scroll view's content object.

Time Elapsed Text: the text object that will display the time elapsed.

Mode Toggle: the toggle that will toggle the mode between load and save mode.

Step 2: Other Script Members

We will create other members that won't be visible in the inspector.

public class InfiniteSavesExample : MonoBehaviour
{
        private const string timeElapsedKey = "TimeElapsed";

        [SerializeField]
        private Button saveSlotPrefab;
        
        [SerializeField]
        private Button saveSlotCreator;
        
        [SerializeField]
        private Transform content;
        
        [SerializeField]
        private Text timeElapsedText;
        
        [SerializeField]
        private Toggle modeToggle;

        private List<Button> slots = new();

        private float timeElapsed;

        private bool loadMode { get => modeToggle.isOn; }
}

timeElapsedKey: the key (or ID) of the time elapsed for saving purposes.

slots: a list of buttons that will store all of the instantiated save slots.

timeElapsed: the time elapsed as a float.

loadMode: the isOn value of the toggle.

If load mode is true, we will make the save slots load a save. If it's false (save mode), we will make the save slots overwrite a save.

Step 3: Instantiate Existing Saves

When we enter play mode, we need to first load any existing saves that the player may have made in a previous session.

We can do this using the Start method.

private void Start()
{
    // Instantiate slots for existing saves
    foreach (var save in SaveStorage.instance.saves.Values) 
    {
        CreateNewSaveSlot(save);
    }
}

Step 4: Increment Time

In the Update method, we will increment the time elapsed. This will be the only data that will be saved and loaded for this example.

private void Update()
{
    // Increment time per frame
    timeElapsed += Time.deltaTime;
    timeElapsedText.text = $"Time Elapsed: {timeElapsed}";
}

Step 5: Saving and Loading Data

We will create 3 methods for saving and loading. The first one will load the data from a save file.

/// <summary>
/// Loads a save.
/// </summary>
/// <param name="saveFile">The save file.</param>
public void LoadSave(SaveFile saveFile)
{
    timeElapsed = saveFile.GetData<float>(timeElapsedKey);
}

The second one will save (or overwrite) the data in the save file.

/// <summary>
/// Overwrites a save.
/// </summary>
/// <param name="saveFile">The save file.</param>
public void OverwriteSave(SaveFile saveFile)
{
    // Save the time elapsed
    saveFile.AddOrUpdateData(timeElapsedKey, timeElapsed);
    saveFile.Save();
}

The third one will be used by the save slots and will load or overwrite the data depending on the mode.

/// <summary>
/// Loads or overwrites the save based on the active mode.
/// </summary>
/// <param name="saveFile">The save file.</param>
public void LoadOrOverwriteSave(SaveFile saveFile)
{
    if (loadMode)
    {
        LoadSave(saveFile);
    }
    else
    {
        OverwriteSave(saveFile);
    }
}

Step 6: Create New Save

We have methods that require a save file, but no save file is being created yet. A save file should be created when the 'Create New Save' button is pressed, along with a save slot.

So, let's create some methods for this. The first method will create a new save file.

/// <summary>
/// Creates a new save.
/// </summary>
public void CreateNewSave()
{
    // Create the save file data
    SaveFileSetupData saveFileSetupData = new()
    {
        fileName = $"InfiniteExampleSave{SaveStorage.instance.saveCount}",
        saveLocation = SaveLocation.DataPath,
        filePath = "StylishEsper/ESave/Examples/Any RP Examples",
        fileType = FileType.Json,
        encryptionMethod = EncryptionMethod.None,
        addToStorage = true
    };

    SaveFile saveFile = new SaveFile(saveFileSetupData);

    // Save the time elapsed
    // Techincally, nothing is being overwitten at this stage since it is an empty save file
    OverwriteSave(saveFile);

    // Create ths save slot for this data
    CreateNewSaveSlot(saveFile);
}

At the end, CreateNewSaveSlot is called. This has not been created yet. The CreateNewSaveSlot method will instantiate a new save slot, edit the save slot's text, and give the save slot an on-click event that will call LoadOrOverwriteSave.

/// <summary>
/// Creates a save slot for a save file.
/// </summary>
/// <param name="saveFile">The save file.</param>
public void CreateNewSaveSlot(SaveFile saveFile)
{
    // Instantiate the save slot
    var slot = Instantiate(saveSlotPrefab, content);
    var slotText = slot.transform.GetChild(0).GetComponent<Text>();
    slotText.text = $"Save Slot {slots.Count}";

    // Move save creator to the bottom
    saveSlotCreator.transform.SetAsLastSibling();

    // Add on-click event for loading
    slot.onClick.AddListener(() => LoadOrOverwriteSave(saveFile));

    slots.Add(slot);
}

We still need the save slot creator button to have an on-click event that creates a new save. This can be done by updating our Start method.

private void Start()
{
    // Instantiate slots for existing saves
    foreach (var save in SaveStorage.instance.saves.Values) 
    {
        CreateNewSaveSlot(save);
    }

    // Save slot creator on-click event
    saveSlotCreator.onClick.AddListener(CreateNewSave);
}

Done! You can now test it in play mode.

Last updated