Handling Saving Player Data

Hi, I have been working on a Save System to save my Players data and that is working fine. However, I’m not sure as to what is the best way to compile all of my Players Data as all of it’s attributes (health, etc.) is split into different classes e.g PlayerHealthManager. Right now I’m pretty sure the way I’m doing it is a complete mess and probably wrong in a lot of places.

I have a base Player class which uses a Singleton and basically holds references to all of the components whose data I need e.g the PlayerHealthManager. I then have a PlayerDataManager class who uses the info from the singleton to compile the Player data into a struct and send it to the SaveSystem, however this feels really messy. Code attached below. If anyone knows of a better way to do things or if this is correct help would be much appreciated

EDIT: Should have mentioned I am serializing the data when I call into the SaveSystem.SavePlayer()

public class PlayerDataManager : MonoBehaviour
{
    public static event Action<PlayerData> OnPlayerDataLoaded = delegate { };

    void Start()
    {
        PlayerData data = (PlayerData)SaveSystem.LoadPlayer();
        OnPlayerDataLoaded(data);
    }

    void OnDisable()
    {
        SavePlayerData();
    }

    public PlayerData GetPlayerData()
    {
        if (Player.instance != null)
        {
            var playerData = new PlayerData();
            Player p = Player.instance;

            // Players Health Fields
            playerData.health = p.HealthManager.Health;
            playerData.maxHealth = p.HealthManager.MaxHealth;

            // Player position fields
            playerData.position = new float[2];
            playerData.position[0] = p.transform.position.x;
            playerData.position[1] = p.transform.position.y;

            return playerData;
        }
        else
        {
            Debug.LogError("No player found");
            return new PlayerData();
        }

    }

    public void SavePlayerData()
    {
        SaveSystem.SavePlayer(GetPlayerData());
    }

}

[System.Serializable]
public struct PlayerData
{
    public float health;
    public float maxHealth;
    public float[] position;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(PlayerHealthManager))]
public class Player : MonoBehaviour
{
    PlayerHealthManager healthManager;
    public static Player instance = null;

    public PlayerHealthManager HealthManager { get { return healthManager; } }
    void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
        else
        {
            Destroy(gameObject);
        }
    }

    void OnEnable()
    {
        healthManager = GetComponent<PlayerHealthManager>();
        PlayerDataManager.OnPlayerDataLoaded += InitializeData;
    }

    void OnDisable()
    {
        PlayerDataManager.OnPlayerDataLoaded -= InitializeData;
    }

    void InitializeData(PlayerData data)
    {
        Vector2 newPosition = new Vector2(data.position[0], data.position[1]);
        transform.position = newPosition;

        healthManager.InitializeData(data);
    }
}

Good thing about your approach is, that you can create your PlayerData for saving / loading and keep all as one class.
This way you can manage player data, or save data (whatever called) independently, from rest of you game.
You just fetch in and out relevant data into that class.
I don’t think is wrong.

Other way, you could use directly JsonUtility for example and it could handle all saved/load classes for you.

1 Like

Thanks for the reply. Yeah, I just wasn’t sure about the scalability if I kept adding scripts to the Player, however I’m not sure if that will be a massive problem.

I’m fairly new to handling data and just wasn’t sure if this approach was correct or not

It depends always.
Meaning how much data will be added etc. But trying different approaches is best way to learn, and find, what suits the best.

Definitely, there is no right, or wrong approach. But some may be better in certain cases, than other.

Another good thing about having single class, is much easier from there, to link, into other saving system, if you ever decide to. And is easier to see, which most important data for saving you have, in one place.

There are other methods as well, but others will be better, to describe them.

What about the world? Your system seems hardcoded for the player, I would create a system thats more generic and can be extended for any type. We do this for network game. So when a new player connects the server sends the current world state

Hi, yes I was going to use separate functions to save data from other places as I’ve never really used generics before but I can see why it would be easier to be able to just call into SaveSystem.Save() and save any data that I needed too.

I think that’s what you are talking about anyway but if it’s not please let me know