Unity 事件详解

  在使用Unity的过程中, 事件(Unity Event)并不复杂,但是容易与很多相近的概念混淆。比如Event System(事件系统),Delegate(委托),C#的Event。

  而UnityEvent其实只是C#委托的一个简单包装。

1. Unity Event 实例

  首先把编程场景固定在一个跳跃动作时需要播放音效的过程。

if(jumping){
    AudioSource audio = GetComponent<AudioSource>;
    audio.clip = Resources.Load<AudioClip>("jump");
    audio.Play();
}

       我们上面的代码是直接把播放声音的代码加进去,但这样的编程方式随着代码的增多后可读性会变差。而且可拓展性也会变差,当需要在玩家跳跃事同步发生其他事件时需要修改这部分代码,破坏了设计模式中的开闭原则(对修改关闭,对拓展开放)。所以上述代码需要进行修改。

// 添加UnityEvent关键字
...
public UnityEvent JumpEvent;
...
// 修改Jump代码
if(jump){
    JumpEvent.Invoke();
}
using UnityEngine

public class PlayerAudio : MonoBehaviour{
    AudioSource audioSource;
    void Start(){
        audioSource = GetComponent<AudioSource>;
        PlatformerCharacter2D cc = GetComponent<PlatformerCharacter2D>();
     // 找到之前的事件,为事件添加监听对象
// 对拓展开放,需要新的监听对象只需要在外面添加就行。 cc.JumpEvent.AddListener(OnPlayerJump); } }

   我们跳跃写成了一个Unity事件,让需要响应的动作写成其他的函数,拓展时只需要为该事件添加监听对象。

2. Unity Event 的多参数形式

  Unity Event不仅可以通过AddListener来订阅函数,还可以通过RemoveListener来删除订阅函数。订阅支持多次添加同一个函数,多添加几次就会多调用几次。如果订阅的函数需要参数,Unity Event也是支持的。

  如下代码,MyEvent1是一种任意事件类型,参数为一个Vector3。

public class MyEvent1 : UnityEvent<Vector3>{}

3.Unity 事件与委托

  UnityAction就是C#语法中的委托。初学者往往有疑问,那就是要实现事件的订阅和调用,使用委托的语法就足够了,根本不需要用到Unity事件。

using UnityEngine

delegate void MyFunc1();
delegate int MyFunc2(int a);

public class TestDelegate : MonoBehaviour{
    void Start(){
        MyFunc1 f1;
        f1 = F;
        MyFunc2 f2;
        f2 = G;
        
        f1();
        f2(3);
    }  
    void F(){
    Debug.log("F");
    }
    int G(int i ){
        Debug.Log("G"+i);
    }
}

  以上就是委托的一段使用语法。delegate使得函数可以作为普通对象使用。有助于实现函数式编程。

  每个委托的定义,必须清楚定义这类函数的参数数量,参数类型以及返回值类型。有了函数类型,就可以定义该变量的函数。除此之外,委托变量也可以通过参数传递或者添加到容器,即普通变量支持的操作,委托变量也能支持。委托的基本用法如下:

void Start(){
    // 将函数用作参数传递。
    CallFunc(F,G,9);
    // 列表,每个元素都是函数的作用
    List<MyFun1> funcs = new List<MyFun1>();
    // 添加
    funcs.Add(f);
    foreach (MyFunc1 f in funcs){
        f();
    }
}
void CallFunc(Myfunc1 f, MyFunc2 g,int n){
  ...
}
 

 拓展用法 

    1.委托作为事件使用

    以下代码中,普通的函数变量g完全可以代替UnityEvent。Addlistener相当于+=。

int GA(int i){
    Debug.log("GA"+i);
    return 0;
}
int GB(int i){
    Debug.log("GB"+i);
    return 0;
}
void Start(){
    Myfunc2 g = null;
    g+=GA;
    g+=GB;
    g(2);
    g+=GA;
    g-=GC;
    g(5);
}

    2.委托与事件的关系 

namespace UnityEngine.Events
{
    public delegate void UnityAction();
    public delegate void UnityAction<T0>(T0 arg0);    
    public delegate void UnityAction<T0,T1>(T0 arg0,T1 arg1);
    public delegate void UnityAction<T0,T1,T2>(T0 arg0,T1 arg1,T2 arg2);
    public delegate void UnityAction<T0,T1,T2,T3>(T0 arg0,T1 arg1,T2 arg2,T3 arg3);
}

    UnityAction是一种事先定义好的委托,也就是一种函数类型。UnityAction支持多个泛型,也可以方便的搭配UnityEvent使用。
 从原理上说,委托可以代替Unity事件。但是在开发时最好使用UnityEvent,因为这符合开发规范并且会更加的便利。

 

posted @ 2023-07-17 14:45  CatSevenMillion  阅读(2085)  评论(0编辑  收藏  举报