Unity GameObject.BroadcastMessage() 不适用于停用的游戏对象

Ten*_*lah 0 c# unity-game-engine

我注意到GameObject.BroadcastMessage当目标被停用时这不起作用。如何调整它以使其在这种情况下工作。

显然,此EventOnMonoCallback.cs脚本附加到TOOTHPANEL,它将触发,OnEnable()_Food游戏对象本身处于非活动状态。

似乎, BroadcastMessage 不适用于停用的孩子?

出于某种原因,TOOTHPANEL直到其他脚本将TOOTHPANEL游戏对象设置为true.

在此处输入图片说明

在此处输入图片说明

EventOnMonoCallback.cs

public class EventOnMonoCallback : MonoBehaviour
{
    public enum MonoCallbackType
    {
        Awake,
        Start,
        Update,
        OnEnable,
        OnDisable,
        OnDestroy
    }

    public MonoCallbackType Type;
    public UnityEvent Do;

    void Awake()
    {
        if (Type == MonoCallbackType.Awake)
        {
            Do.Invoke();
        }
    }

    void Start()
    {
        if (Type == MonoCallbackType.Start)
        {
            Do.Invoke();
        }
    }

    void Update()
    {
        if (Type == MonoCallbackType.Update)
        {
            Do.Invoke();
        }
    }

    void OnEnable()
    {
        if (Type == MonoCallbackType.OnEnable)
        {
            Do.Invoke();
        }
    }

    void OnDisable()
    {
        if (Type == MonoCallbackType.OnDisable)
        {
            Do.Invoke();
        }
    }

    void OnDestroy()
    {
        if (Type == MonoCallbackType.OnDestroy)
        {
            Do.Invoke();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Pro*_*mer 5

在 Unity 中激活/停用和启用/禁用之间存在差异。您可以激活和停用游戏对象。您可以启用和禁用脚本。不要混淆这两者。

BroadcastMessage功能将一直工作即使与目标功能的脚本是禁用的,但它将工作的时候游戏对象该脚本连接到被停用


有两种简单的解决方法:

1Invoke .使用Unity的内置函数。使用GetComponentsInChildren获取所有MonoBehaviour然后调用Invoke每个。即使 GameObject 被停用,调用也将始终有效。使用该GetComponentsInChildrentakeList作为参数的重载版本,以便每次调用时都不会产生垃圾。

List<MonoBehaviour> monoList = new List<MonoBehaviour>();


void BroadcastMessageExt(string methodName)
{
    targetObj.GetComponentsInChildren<MonoBehaviour>(true, monoList);
    for (int i = 0; i < monoList.Count; i++)
    {
        monoList[i].Invoke(methodName, 0);
    }
}
Run Code Online (Sandbox Code Playgroud)

唯一不好的是你不能向它传递参数。有关解决方法,请参阅#2


2 .做与#1相同的事情,但使用C#MethodInfo.Invoke函数而不是Unity API的版本。这应该让您将参数传递给您正在调用的函数。

List<MonoBehaviour> monoList = new List<MonoBehaviour>();


void BroadcastMessageExt(string methodName, object value = null, SendMessageOptions options = SendMessageOptions.RequireReceiver)
{
    targetObj.GetComponentsInChildren<MonoBehaviour>(true, monoList);
    for (int i = 0; i < monoList.Count; i++)
    {
        try
        {
            Type type = monoList[i].GetType();

            MethodInfo method = type.GetMethod(methodName, BindingFlags.Instance |
                                            BindingFlags.NonPublic |
                                             BindingFlags.Public |
                                             BindingFlags.Static);

            method.Invoke(monoList[i], new object[] { value });
        }
        catch (Exception e)
        {
            //Re-create the Error thrown by the original SendMessage function
            if (options == SendMessageOptions.RequireReceiver)
                Debug.LogError("SendMessage " + methodName + " has no receiver!");

            //Debug.LogError(e.Message);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以将这些转换为扩展方法,使它们更易于使用。