GameObject property value not resetting on game restart

Viewed 488

Overview
Consider a simple coin collecting game. There are two scripts, CollectableItem and ItemVault. The CollectableItem has a value property which tells the item's worth and it is added to the coin prefab. The ItemVault has a CurrentAmount property which stores the total value of collected coins and it is added to the player prefab.

Problem
The value of CurrentAmount property of ItemVault object does not reset on game restart inside Unity Editor.

Code

CollectableItem.cs

public class CollectableItem : MonoBehaviour
{
    public float value = 1f;
    public ItemVault vault;

    private ItemVault m_vault;

    void Start()
    {
        m_vault = vault.GetComponent<ItemVault>();
        Debug.Log(m_vault.CurrentAmount); //Does not reset
    }

    //isTrigger
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if(vault != null)
        {
            m_vault.ChangeAmountBy(this.value);
        }
        Destroy(gameObject);
    }
}

ItemVault.cs

public class ItemVault : MonoBehaviour
{
    public float startingAmount; // 0

    public float CurrentAmount { get; private set; }

    void Start()
    {
        CurrentAmount = startingAmount;
        Debug.Log(CurrentAmount); // 0
    }

    public void ChangeAmountBy(float amount)
    {
        CurrentAmount += amount;
        Debug.Log(CurrentAmount); // CurrentAmount does not reset
    }
}

Note

  1. Both CollectableItem and ItemVault are added to prefabs.
  2. The Start function of ItemVault does log the value of CurrentAmount as 0 but the Start function of CollectableItem logs the last value of CurrentAmount in previous run.
  3. Restarting the editor itself resets the value.
  4. I've tried changing the Script Execution Order to call ItemVault before CollectableItem
  5. Instantiating the properties in Awake() instead of Start() is giving the same results
1 Answers

First of all:

Make sure in _vault you are actually referencing an existing object reference in the scene, not a prefab asset - otherwise, yes you will be executing the method on the prefab instead which will not be reset on Scene load / Exiting PlayMode.

You can confirm that by starting PlayMode and then in the Hierarchy click once on the vault slot in the Inspector. This will highlight the referenced object either in the Hierarchy (expected) or in the Assets (should not happen!).


If this didn't help then your problem might be a timing issue.

If your CollectableItem.Start is executed before ItemVault.Start got its chance to execute you might see different values.

I usually go with the thumb-rule

  • Awake: Initialize yourself, so anything that does not depend on others
  • Start: Now access values of other components which have already been initialized in Awake

So In your case I would do

public class CollectableItem : MonoBehaviour
{
    public float value = 1f;

    // In general rather already reference this via the Inspector
    [SerializeField] private ItemVault _vault;

    private void Awake()
    {
        // Ass fallback get it on runtime
        if(!_vault) _vault = vault.GetComponent<ItemVault>();
    }

    private void Start()
    {
        Debug.Log(_vault.CurrentAmount);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if(_vault)
        {
            _vault.ChangeAmountBy(this.value);
        }
        Destroy(gameObject);
    }
}

and

public class ItemVault : MonoBehaviour
{ 
    [SerializeField] private float startingAmount; // 0

    public float CurrentAmount { get; private set; }

    private void Awake()
    {
        CurrentAmount = startingAmount;
        Debug.Log(CurrentAmount);
    }

    public void ChangeAmountBy(float amount)
    {
        CurrentAmount += amount;
        Debug.Log(CurrentAmount);
    }
}
Related