首页 > 解决方案 > GameObject 属性值不会在游戏重新启动时重置

问题描述

概述
考虑一个简单的硬币收集游戏。有两个脚本,CollectableItemItemVault. 有CollectableItem一个value属性,它告诉项目的价值,它被添加到coin预制件中。有ItemVault一个CurrentAmount属性来存储收集到的硬币的总价值,并将其添加到player预制件中。

问题ItemVault对象的CurrentAmount属性的
值不会在 Unity 编辑器内重新启动游戏时重置。

代码

收藏品.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
    }
}

笔记

  1. CollectableItem和都ItemVault添加到prefabs.
  2. Start函数ItemVault确实记录CurrentAmountas的值,0但记录上次运行的最后一个值的Start函数。CollectableItemCurrentAmount
  3. 重新启动编辑器本身会重置该值。
  4. 我之前尝试过更改toScript Execution Order调用ItemVaultCollectableItem
  5. 实例化属性Awake()而不是Start()给出相同的结果

标签: c#unity3dproperties

解决方案


首先:

确保_vault您实际上是在引用场景中的现有对象引用,而不是预制资产 - 否则,是的,您将在预制上执行该方法,而不是在场景加载/退出 PlayMode 时重置。

您可以通过启动 PlayMode 来确认这一点,然后在 Hierarchy 中单击vaultInspector 中的插槽一次。这将突出显示层次结构(预期)或资产(不应该发生!)中的引用对象。


如果这没有帮助,那么您的问题可能是时间问题。

如果您在有机会CollectableItem.Start执行之前执行,您可能会看到不同的值。 ItemVault.Start

我通常使用拇指规则

  • Awake:初始化自己,所以任何不依赖别人的东西
  • Start: 现在访问已经在 Awake 中初始化的其他组件的值

所以在你的情况下,我会做

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);
    }
}

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);
    }
}

推荐阅读