【问题标题】:Trigger a function when array values are changed更改数组值时触发函数
【发布时间】:2021-01-20 12:43:59
【问题描述】:

我正在通过检查器窗口添加一组数组值。当我更改数组值时,我试图实现触发功能。也就是说,我的脚本应该检查新值是否不等于旧值,然后调用此函数。 我不想使用 Update,因为它会占用更多内存和处理能力,那么还有什么替代方法?


public class SetValues : MonoBehaviour {

    [Serializable]
    public struct SetValues
    {
        public float Position;
        public float Value;
    }
 
    public SetValues[] setValues;


    void Function_ValuesChanged()
    {
        Debug.Log("The Value is changed");
        //Do Something
    }

}

【问题讨论】:

  • 如果有帮助,这里有一个简单的 Unity 事件教程:stackoverflow.com/a/36249404/294884
  • @Fattie Unity 事件和 C# 事件不一样。在这种情况下,您不能使用 Unity 事件。 Unity Events 的预期使用领域是 UI 交互。
  • 嗨@SeLeCtRa - 我不知道你在说什么,这没有任何意义。 (对不起!)要在值更改时触发某些内容,您只需使用属性(如您的答案中所述)。这就是问题的答案。 (就像你的好答案一样!)当然,在那之后,你很可能会使用一个事件 - 所以我只是放入链接来帮助 OP。
  • 我并不是要冒犯你,伙计。我们只是在讨论,我知道您需要帮助,但据我所知 Unity Event System 并非如此。我只是写评论,因为如果有人看到并尝试它,它不会按预期工作,因为 UI 和脚本之间的交互是不同的层。如果我错了,请纠正我。如果可能的话,我也渴望以这种方式学习。
  • 顺便说一句,我对讨论感到困惑,但 UnityEvents 不仅适用于 Unity.UI 吗?您可以将它们用于 Unity 中的任何单一行为(我相信!)

标签: c# unity3d


【解决方案1】:

试试MonoBehavior.OnValidate()

例子:

public class SetValues : MonoBehaviour {

[Serializable]
public struct SetValues
{
    public float Position;
    public float Value;
}

public SetValues[] setValues;


void OnValidate()
{
    Debug.Log("The Value is changed");
    //Do Something
}

}

【讨论】:

  • 如果您只想在检查器中发生这种情况,这是最好的答案。小心 OnValidate 函数,因为它仅在检查器更改事件时调用。它永远不会在您构建的可执行文件中被调用...
  • 如果从服务器更改了值怎么办?既然被声明为public,还是会被调用吧?
  • @Techno ,不,那是错误的。 avokado 说的是正确的。您需要的只是一个 Property - 如其他答案中所述
  • @Techno , "OnValidate" 纯粹是 MonoBehavior 函数 - 它实际上是 Inspector 的一部分:docs.unity3d.com/ScriptReference/MonoBehaviour.OnValidate.html 它不是 C# 中的“通用”函数或任何东西像这样。
【解决方案2】:

如果游戏中发生某些事情并且您想通知其他脚本使用事件。事件轻量级且易于实现。

在包含数组的类中,仅从属性创建属性和更改数组值。永远不要直接与数组字段交互。

// Create Event Arguments
    public class OnArrayValueChangedEventArgs : EventArgs
    {
        public float Position;
        public float Value;
    }
    // Crate Event
    public event EventHandler<OnArrayValueChangedEventArgs> OnArrayValueChanged;
    
    Array[] myArray;
    // Change Array value only from this property, so when you change value, event will be called
    public Array[] MyArray
    {
        get { return myArray; }
        set { myArray = value; OnArrayValueChangedEvent(this, new OnArrayValueChangedEventArgs() { Position = myArray.Position, Value = myArray.Value };}
    }

从第二课开始,你应该订阅这个事件并做这件事。我将从我的 GameManager Singleton 类中调用此事件。

private void Awake()
{
    GameManager.Instance.OnArrayValueChanged += Instance_OnArrayValueChanged;
}

private void Instance_OnArrayValueChanged(object sender, GameManager.OnArrayValueChangedEventArgs e)
{
    // Do the thing
}

【讨论】:

  • 仅供参考 在游戏引擎中不可能有“单例”。
  • @Fattie 你能详细说明一下吗?保存一个实例的标准模式静态变量在 Unity 中仍然有效。是否应该使用单例是另一个问题。我个人会说有少数用例。例如,我用它来存储全局用户首选项\设置以及“菜单打开”等粗略状态。
  • @Fattie 对不起,伙计,但怎么会?你知道什么是单例吗?单例是你只能拥有一个脚本拥有的类。我有 GameManager、ResourceManager、ProductionManager 等,可能有 20 个或更多单例类。单例模式确保您只有 1 个实例,并且您可以轻松访问变量。到目前为止没有问题。但是我的用例有点特殊,所以在许多类型的游戏中单例使用较少,但这并不意味着您不能使用单例。这只是编程模式。
  • 您不能在 Unity 中拥有单例组件 .. MonoBehavior .. 在游戏引擎或任何 ECS 系统中。这完全没有意义。
  • @Fattie Singleton 不是组件类型,它是编程模式。这是我的单例课程。使用 UnityEngine;公共抽象类 Singleton : MonoBehaviour where T : MonoBehaviour { private static T instance; public static T Instance { get { if (instance == null) { instance = FindObjectOfType(); } 返回实例; } } } 这只是带有额外步骤的 Monobehaviour。它确保只有 1 个实例并且可以轻松访问变量。没什么神奇的。
猜你喜欢
  • 1970-01-01
  • 2016-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-23
  • 1970-01-01
  • 2014-12-15
  • 2011-11-03
相关资源
最近更新 更多