Home > OS >  Initialize Serializable Class
Initialize Serializable Class

Time:10-24

I have a controller class for the health of a GameObject. It is not a MonoBehavior but it will be used by MonoBehavior objects.

using System;
using UnityEngine;

[Serializable]
public class HealthController{
    [SerializeField]
    private int max_health;
    private int health;
    
    public HealthController {
        this.health = this.max_health; // this doesnt work because its called before serialisation
    }
}

so I want to be able to set the maximum health in the unity editor: thats why max_health is a SerializeField. But now i also want the variable health initally to be set to the the maximum health without introducing a second SerializeField for it. Thats why I tried to put the line this.health = this.max_health to the constructor: but this doesn#t work because the constructor seems to be called before the serialisation.

The only solution i could think of is adding a public void Initialize() instead of the contructor to the HealthController and then explicitly calling this in the Start() method of the Monobehavior owning this controller.

using System;
using UnityEngine;

[Serializable]
public class HealthController{
    [SerializeField]
    private int max_health;
    private int health;
    
    public void Initialize() {
        this.health = this.max_health;
    }
}


public class Player : MonoBehaviour
{
    public HealthController health;

    public void Start() {
        health.Initialize(); 
    }

}

But this seems too complicated to me: Is there a better solution on how to do this?

CodePudding user response:

If you use lazy initialization, you don't need to worry about explicitly initializing HealthController objects. You could mark health as a nullable with ? and then route access it through a property:

private int? health;

public int Health {
    get {
        if (!health.HasValue) {
             health = max_health;
        }
        return health.Value;
    }
    private set {
        health = value;
    }
}

CodePudding user response:

You can add the ISerializationCallbackReceiver interface to your HealthController object. Admittedly, this might be a bulldozer, when all you need is a hammer. But, the functionality Unity provides when you implement the interface can often help a project.

You then use it like:

[Serializable]
public class HealthController : ISerializationCallbackReceiver
{
    [SerializeField]
    private int max_health;
    private int health;

    // required to satisfy the interface requirements.
    public void OnBeforeSerialize() { }

    public void OnAfterDeserialize ()
    {
        health = max_health;
        // .. then any further post deserialisation work you might want to do.
    }
}

Here’s the Unity docs for ISerializationCallbackReceiver.

  • Related