初面网初面网

消息

在Unity中,游戏对象可以通过多种方式向自己发送消息,实现脚本内部的方法调用和逻辑触发。以下是几种常用的方法:

1. 直接方法调用

这是最直接、最简单的方式,适用于同一脚本内的方法调用。

public class ExampleScript : MonoBehaviour
{
    private void Start()
    {
        // 直接调用自身的方法
        DoSomething();
    }

    private void DoSomething()
    {
        Debug.Log("直接调用方法");
    }
}

2. 使用 Invoke 和 InvokeRepeating

适用于需要延迟执行或重复执行的场景。

public class ExampleScript : MonoBehaviour
{
    private void Start()
    {
        // 延迟2秒后调用DoSomething方法
        Invoke("DoSomething", 2f);
        
        // 延迟1秒后,每3秒调用一次DoRepeating方法
        InvokeRepeating("DoRepeating", 1f, 3f);
    }

    private void DoSomething()
    {
        Debug.Log("延迟调用方法");
    }

    private void DoRepeating()
    {
        Debug.Log("重复调用方法");
    }
}

3. 使用 SendMessage 系列方法

通过字符串名称调用方法的系列方法,包括SendMessage、SendMessageUpwards和BroadcastMessage。

3.1 SendMessage

向自身发送消息,适用于需要通过字符串名称调用方法的场景。

SendMessage是GameObject的方法,用于向自身发送消息。 该方法会查找所有挂载在游戏对象上的脚本,查找是否有匹配的方法名。 如果找到匹配的方法,会调用该方法。 如果没有找到匹配的方法,会抛出异常。

public class ExampleScript : MonoBehaviour
{
    private void Start()
    {
        // 向自身发送消息,调用DoSomething方法
        SendMessage("DoSomething");
        
        // 向自身发送消息,调用带参数的方法
        SendMessage("DoSomethingWithParam", "Hello");
    }

    private void DoSomething()
    {
        Debug.Log("通过SendMessage调用方法");
    }

    private void DoSomethingWithParam(string message)
    {
        Debug.Log("通过SendMessage调用带参数的方法: " + message);
    }
}

3.2 SendMessageUpwards

向自身及其所有父对象发送消息,适用于需要向对象层级上方发送消息的场景。

SendMessageUpwards是GameObject的方法,用于向自身及其所有父对象发送消息。 该方法会查找所有挂载在游戏对象及其父对象上的脚本,查找是否有匹配的方法名。 如果找到匹配的方法,会调用该方法。 如果没有找到匹配的方法,会抛出异常。

public class ChildScript : MonoBehaviour
{
    private void Start()
    {
        // 向自身及其所有父对象发送消息,调用DoSomething方法
        SendMessageUpwards("DoSomething");
        
        // 向自身及其所有父对象发送消息,调用带参数的方法
        SendMessageUpwards("DoSomethingWithParam", "Hello from child");
    }

    private void DoSomething()
    {
        Debug.Log("子对象通过SendMessageUpwards调用方法");
    }

    private void DoSomethingWithParam(string message)
    {
        Debug.Log("子对象通过SendMessageUpwards调用带参数的方法: " + message);
    }
}

public class ParentScript : MonoBehaviour
{
    private void DoSomething()
    {
        Debug.Log("父对象通过SendMessageUpwards调用方法");
    }

    private void DoSomethingWithParam(string message)
    {
        Debug.Log("父对象通过SendMessageUpwards调用带参数的方法: " + message);
    }
}

3.3 BroadcastMessage

向自身及其所有子对象发送消息,适用于需要向整个对象层级发送消息的场景。

BroadcastMessage是GameObject的方法,用于向自身及其所有子对象发送消息。 该方法会查找所有挂载在游戏对象及其子对象上的脚本,查找是否有匹配的方法名。 如果找到匹配的方法,会调用该方法。 如果没有找到匹配的方法,会抛出异常。

public class ParentScript : MonoBehaviour
{
    private void Start()
    {
        // 向自身及其所有子对象发送消息,调用DoSomething方法
        BroadcastMessage("DoSomething");
        
        // 向自身及其所有子对象发送消息,调用带参数的方法
        BroadcastMessage("DoSomethingWithParam", "Hello from parent");
    }

    private void DoSomething()
    {
        Debug.Log("父对象通过BroadcastMessage调用方法");
    }

    private void DoSomethingWithParam(string message)
    {
        Debug.Log("父对象通过BroadcastMessage调用带参数的方法: " + message);
    }
}

public class ChildScript : MonoBehaviour
{
    private void DoSomething()
    {
        Debug.Log("子对象通过BroadcastMessage调用方法");
    }

    private void DoSomethingWithParam(string message)
    {
        Debug.Log("子对象通过BroadcastMessage调用带参数的方法: " + message);
    }
}

4. 使用事件系统

适用于需要解耦的场景,通过C#事件实现消息传递。

public class ExampleScript : MonoBehaviour
{
    // 定义事件
    public event Action OnSelfMessage;
    public event Action<string> OnSelfMessageWithParam;

    private void Start()
    {
        // 订阅事件
        OnSelfMessage += DoSomething;
        OnSelfMessageWithParam += DoSomethingWithParam;
        
        // 触发事件
        OnSelfMessage?.Invoke();
        OnSelfMessageWithParam?.Invoke("Hello from event");
    }

    private void DoSomething()
    {
        Debug.Log("通过事件调用方法");
    }

    private void DoSomethingWithParam(string message)
    {
        Debug.Log("通过事件调用带参数的方法: " + message);
    }
}

5. 使用 ExecuteEvents(UI系统)

适用于UI元素的消息传递,需要使用UnityEngine.EventSystems命名空间。

using UnityEngine;
using UnityEngine.EventSystems;

public class ExampleUI : MonoBehaviour, IPointerClickHandler
{
    private void Start()
    {
        // 模拟点击自身
        ExecuteEvents.Execute(this.gameObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerClickHandler);
    }

    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("UI元素接收到点击事件");
    }
}

最佳实践

  1. 直接方法调用:最常用、性能最好,适用于大多数场景。
  2. Invoke:适用于需要延迟执行的场景,但性能略低于直接调用。
  3. SendMessage系列方法:包括SendMessage、SendMessageUpwards和BroadcastMessage,灵活性高,但性能较差,不建议在频繁调用的场景使用。
  4. 事件系统:适用于需要解耦的复杂系统,代码结构更清晰。
  5. ExecuteEvents:专门用于UI系统的事件传递。

根据具体场景选择合适的方法,可以提高代码的可读性和性能。

更新于 2026/2/26