【问题标题】:GameObject property value not resetting on game restartGameObject 属性值不会在游戏重新启动时重置
【发布时间】:2020-07-03 16:01:45
【问题描述】:

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

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

代码

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

注意

  1. CollectableItemItemVault 都添加到 prefabs
  2. ItemVaultStart 函数确实将CurrentAmount 的值记录为0,但CollectableItemStart 函数记录了上次运行中CurrentAmount 的最后一个值。
  3. 重新启动编辑器本身会重置该值。
  4. 我尝试将Script Execution Order 更改为在CollectableItem 之前调用ItemVault
  5. Awake() 而不是 Start() 中实例化属性会得到相同的结果

【问题讨论】:

  • 您所说的预制件是指实际的预制件(=资产)或这些在场景中的实例? game restart 是指退出和进入 PlayMode 还是你的场景中有一些重启功能?
  • 还要注意vaultm_vault 是多余的......你已经有一个ItemVault 引用,所以不需要/使用再次调用GetComponent&lt;ItemVault&gt;()
  • @derHugo 是的预制件我的意思是Assets 游戏重启我的意思是退出和进入播放模式

标签: c# unity3d properties


【解决方案1】:

首先:

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

您可以通过启动 PlayMode 并在 Hierarchy 中单击 Inspector 中的 vault 插槽来确认这一点。这将在 Hierarchy(预期)或 Assets(不应该发生!)中突出显示引用的对象。


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

如果您的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);
    }
}

【讨论】:

  • 我在 Awake() 函数中初始化了变量,仍然在 Awake()CollectableItem 中获取旧值。
  • 我也尝试通过Unity编辑器项目设置更改脚本执行顺序,在CollectableItem.cs之前调用ItemVault.cs,还是没有成功
  • 如你所见,我说过你应该调试Start 中的值,而不是Awake,因为CollectableItem.Awake 中的值可能还没有初始化
  • 这就是我正在做的 ;-) 我实际上尝试了两种方式。结果相同。加上ChangeAmountBy(float) 函数每次也会给出旧值,这让我想知道问题是否与我正在通过检查器的vault 引用有关。
  • 那么你正在改变预制件......这永远不会重置。重新启动编辑器时,您只是没有保存;)确保您只引用场景中对象的组件......或者换句话说:您为什么要在那里引用预制件?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-19
  • 1970-01-01
  • 1970-01-01
  • 2019-05-11
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多