ESave
ESave Pro
ESave Pro
  • ESave Pro Documentation
  • Pro Comparison
  • đŸ•šī¸Getting Started
    • Installation
    • Demo
  • ESave Settings
  • 🧩Components
    • ESave Initializer
  • 📄Scripting
    • Initialization
    • Save Operation
    • Save States
      • Infinite Saves
        • Infinite Save Scripting
    • Saving & Loading Data
      • Saving
      • Loading
      • Custom Serializable Objects
      • Example Script
    • Data Deletion
  • đŸ› ī¸Support
    • Getting Help
  • 📚Changelogs
    • Latest Releases
  • ⭐Rate Me?
Powered by GitBook
On this page
  • Step 1: Create a Script
  • Step 2: Other Script Members
  • Step 3: Initialize ESave
  • Step 4: Instantiate Existing Saves
  • Step 5: Increment Time
  • Step 6: Saving and Loading Data
  • Step 7: Create New Save
  • Step 8: Delete All Saves
  • Step 9: Final Button Events
  1. Scripting
  2. Save States
  3. Infinite Saves

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
{
    /// <summary>
    /// The save slot prefab.
    /// </summary>
    [SerializeField]
    private Button saveSlotPrefab;
    
    /// <summary>
    /// A button that creates a new save state.
    /// </summary>
    [SerializeField]
    private Button createSaveButton;
    
    /// <summary>
    /// A button that deletes all save states.
    /// </summary>
    [SerializeField]
    private Button deleteAllButton;
    
    /// <summary>
    /// Parent transform of save slots.
    /// </summary>
    [SerializeField]
    private Transform content;
    
    /// <summary>
    /// Text that displays the time elapsed.
    /// </summary>
    [SerializeField]
    private Text timeElapsedText;
    
    /// <summary>
    /// A toggle that controls the save/load mode. If toggled on, clicking on a save slot will load it. If toggled off,
    /// clicking on a save slot will overwrite the save.
    /// </summary>
    [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. Drag and drop each component to the relevant property.

Step 2: Other Script Members

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

public class InfiniteSavesExample : MonoBehaviour
{
    /// <summary>
    /// Time elapsed data ID.
    /// </summary>
    private const string timeElapsedID = "TimeElapsed";
    
    /// <summary>
    /// The save slot prefab.
    /// </summary>
    [SerializeField]
    private Button saveSlotPrefab;
    
    /// <summary>
    /// A button that creates a new save state.
    /// </summary>
    [SerializeField]
    private Button createSaveButton;
    
    /// <summary>
    /// A button that deletes all save states.
    /// </summary>
    [SerializeField]
    private Button deleteAllButton;
    
    /// <summary>
    /// Parent transform of save slots.
    /// </summary>
    [SerializeField]
    private Transform content;
    
    /// <summary>
    /// Text that displays the time elapsed.
    /// </summary>
    [SerializeField]
    private Text timeElapsedText;
    
    /// <summary>
    /// A toggle that controls the save/load mode. If toggled on, clicking on a save slot will load it. If toggled off,
    /// clicking on a save slot will overwrite the save.
    /// </summary>
    [SerializeField]
    private Toggle modeToggle;
    
    /// <summary>
    /// A list of loaded save slots.
    /// </summary>
    private List<Button> slots = new();
    
    /// <summary>
    /// The amount of time elapsed.
    /// </summary>
    private float timeElapsed;
    
    /// <summary>
    /// If load mode is enabled.
    /// </summary>
    private bool loadMode { get => modeToggle.isOn; }

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: Initialize ESave

You can either add the ESave Initializer component to your scene or add the code below to your script.

private void Awake()
{
    // Initialize ESave
    ESave.Initialize();
}

private void OnApplicationQuit()
{
    // End database connection
    ESave.Terminate();

    // Unload active save if it exists
    if (SaveState.active != null)
    {
        ESave.Unload();
    }
}

The idea is just to initialize ESave on awake and terminate it on exit.

Step 4: 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 in the Start method.

Also, save slot UI objects will need to be instantiated for this, so we'll create a method called CreateNewSaveSlot that will do just that.

private void Start()
{
    // Get all save states
    ESave.GetAllSaveStates().OnComplete(result =>
    {
        // Create slots for existing save states
        foreach (var existingSave in result)
        {
            CreateNewSaveSlot(existingSave);
        }
    });
}

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

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

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

    slots.Add(slot);
}

Step 5: 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:0.00}";
}

Step 6: Saving and Loading Data

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

/// <summary>
/// Loads a save.
/// </summary>
/// <param name="saveState">The save state.</param>
public void LoadSave(SaveState saveState)
{
    saveState.GetData<float>(timeElapsedID).OnComplete(result =>
    {
        timeElapsed = result;
    });
}

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

/// <summary>
/// Overwrites a save.
/// </summary>
/// <param name="saveState">The save state.</param>
public void OverwriteSave(SaveState saveState)
{
    // Ensure it's the active save to allow editing
    ESave.Load(saveState).OnComplete(result =>
    {
        // Save the time elapsed
        result.AddData(timeElapsedID, timeElapsed).OnComplete(_ =>
        {
            // Confirm changes
            ESave.Save(result);
        });
    });
}

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 state based on the active mode.
/// </summary>
/// <param name="saveState">The save state.</param>
public void LoadOrOverwriteSave(SaveState saveState)
{
    if (loadMode)
    {
        LoadSave(saveState);
    }
    else
    {
        OverwriteSave(saveState);
    }
}

Step 7: Create New Save

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

So, let's create a method for this.

/// <summary>
/// Creates a new save.
/// </summary>
public void CreateNewSave()
{
    // Create a new save state
    ESave.CreateSave().OnComplete(result =>
    {
        // Save the time elapsed
        // Techincally, nothing is being overwitten at this stage since it is an empty save
        OverwriteSave(result);

        // Create the save slot
        CreateNewSaveSlot(result);
    });
}

Step 8: Delete All Saves

At this point, we can create saves, but we can't delete them. Let's add some code that will delete all saves that exist.

/// <summary>
/// Deletes all save states.
/// </summary>
public void DeleteAllSaves()
{
    // Delete all save states
    ESave.DeleteAllSaves().OnComplete(result =>
    {
        // Remove UI objects
        foreach (var slot in slots)
        {
            Destroy(slot.gameObject);
        }

        slots.Clear();
    });
}

Step 9: Final Button Events

We still need the create save button and the delete button to execute the correct methods on-click. This can be done by adding an Awake method. Exclude the initialization code if your using the ESave Initializer component.

private void Awake()
{
    // Initialize ESave
    ESave.Initialize();

    // Add button events
    createSaveButton.onClick.AddListener(CreateNewSave);
    deleteAllButton.onClick.AddListener(DeleteAllSaves);
}

Done! You can now test it in play mode.

PreviousInfinite SavesNextSaving & Loading Data

Last updated 2 months ago

📄