Action
代码,而本人委托那一块自己写的时候压根不会用……遂学习相关知识。using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestMyDelegate : MonoBehaviour
{
public delegate void DeleFunc(int x);
// Start is called before the first frame update
void Start()
{
DeleFunc deleFunc;
deleFunc = show;
deleFunc(10);
deleFunc(8);
deleFunc = doubleShow;
deleFunc(10);
}
void show(int x)
{
Debug.Log(x);
}
void doubleShow(int x)
{
Debug.Log(x * 2);
}
}
DeleFunc
(就如一个函数指针),使用到关键字 delegate
deleFunc
show
,注意这里形参和返回值需要和委托的一致deleFunc
指向 show
,进行方法回调doubleShow
,同理,进行方法回调+=
为同一个委托监听多个方法回调-=
删除一个监听方法using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestMyDelegate : MonoBehaviour
{
public delegate void DeleFunc(int x);
// Start is called before the first frame update
public DeleFunc deleFunc;
void Start()
{
deleFunc += show;
deleFunc += doubleShow;
deleFunc(5);
deleFunc -= doubleShow;
deleFunc(5);
}
void show(int x)
{
Debug.Log(x);
}
void doubleShow(int x)
{
Debug.Log(x * 2);
}
}
public delegate void DeleFunc(int x);
// Start is called before the first frame update
void Start()
{
DeleFunc deleFunc; // 不能写到里面来,会报错 [使用了未赋值的局部变量“deleFunc”]
deleFunc += show;
deleFunc += doubleShow;
deleFunc(5);
}
eat(),drink(),sleep()
,行为越来越多,相应的调用代码也越来越长class Service{
void eat(){// something}
void drink(){// something}
void sleep(){// something}
public void service(string name){
switch (name){
case "eat":eat();break;
case "drink":drink();break;
case "sleep":sleep();break;
}
}
}
若使用委托进行封装,便可以
class Service{
void eat(){// something}
void drink(){// something}
void sleep(){// something}
public delegate void action();
public void service(action act){
act();
}
}
调用的时候,这样:
action act = eat();
Service.service(act);
Service.service(cook);
GameOver()
,但我目前还不知道该函数里面还需要一些代码和方法public void GameOver(){
GamePause();
PlaySound("death");
ClearFlags();
AddDeathCount(1);
ShowGameOverPanel();
// ……
}
public delegate void GameOver();
public GameOver gameOver;
接下来,比如在音效系统的代码中,为其增添回调函数
class VoiceManager{
// ……
public void addSounds(){
gameOver += PlaySound("death");
}
public void PlaySound(string name){
// ……
}
}
其他系统同理。这样,对于需要更改音效的地方,就集中统一管理到了相应的类。
但注意,这里的 gameOver
的委托实例获取方式仍然有些耦合。需要更解耦貌似还需要使用后续提到其他的内容。
C#
的内容,并且事件是一种特殊的委托TestMyDelegate
,代码同上述AnotherDelegate
,相对第一个类,为一个外部类(这里指委托没有声明在该类)using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestMyDelegate : MonoBehaviour
{
public delegate void DeleFunc(int x);
// Start is called before the first frame update
public DeleFunc deleFunc;
void Start()
{
deleFunc += show;
deleFunc += doubleShow;
deleFunc(1);
}
void show(int x)
{
Debug.Log(x);
}
void doubleShow(int x)
{
Debug.Log(x * 2);
}
}
/*****************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AnotherDelegate : MonoBehaviour
{
void Start()
{
TestMyDelegate test = GetComponent<TestMyDelegate>();
test.deleFunc += myfunc;
test.deleFunc(100);
}
void myfunc(int x)
{
Debug.Log(x * 3);
}
}
300
event
关键字,改成事件public event DeleFunc deleFunc;
=
。等于的功能即令该委托/事件只监听这个回调函数。Unity
中的内容,为 Unity
做的一个小封装。UnityEngine.Events
,然后写一下 UnityEvent
,然后 F12
查看源代码UnityEvent
相较于委托,它规范化了 +=和-=
,以 OO 的方式改为了 AdListener(UnityAction call)
和 RemoveListener(UnityAction call)
,除此之外好处是更容易调试debug,编辑器可视化等。UnityEvent
与其他系统 (如 UnityAction
, EventSystem
等)结合,更加方便。UnityEvent
事件,分别监听了无参函数、一参函数和三个参数函数using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class TestUnityEvent : MonoBehaviour
{
public UnityEvent myEvent;
public UnityEvent<int> anotherEvent;
public UnityEvent<int, int, int> alsoEvent;
// Start is called before the first frame update
void Start()
{
myEvent.AddListener(noArg);
myEvent.Invoke();
anotherEvent.AddListener(show);
anotherEvent.Invoke(5);
alsoEvent.AddListener(threeArgs);
alsoEvent.Invoke(1, 2, 3);
}
void show(int x)
{
Debug.Log(x);
}
void noArg()
{
Debug.Log("No Arg");
}
void threeArgs(int a, int b, int c)
{
Debug.Log(a + " " + b + " " + c);
}
}
Action
为 C#
在 System
库中的内容Action
,F12
查看原码Action
就是一个委托。Action<>
再 F12
进去看,则会显示public delegate void myAction(T obj);
,那么该 myAction
和 Action
就没有区别。using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using System;
public class TestAction : MonoBehaviour
{
public Action<int> myAction;
// Start is called before the first frame update
void Start()
{
myAction = show;
myAction += show;
myAction(100);
}
void show(int x)
{
Debug.Log(x);
}
}
在看这个,这个明显就是 Unity
中的一个 Action
头文件在 UnityEngine.Events
中,我们进入查看原码
呃呃呃,你们都那么简单,好吧。
那对比,Action
和 UnityAction
只有头文件不同的区别了,其他的部分都一样啊。
System
,我们查看原码Action
,Func
即多了一个返回值的地方,原来他们都这么简单…using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using System;
public class TestFunc : MonoBehaviour
{
public Func<string, int> func; // 这里的 int 就是返回类型
// Start is called before the first frame update
void Start()
{
func += show;
Debug.Log(func("Hello World"));
}
int show(string x)
{
Debug.Log(x);
return 12;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class TestOtherMethods : MonoBehaviour
{
public UnityAction<int, int> myAction;
// Start is called before the first frame update
void Start()
{
// anony-
myAction = delegate (int x, int y)
{
Debug.Log(x + " " + y);
};
myAction(1, 2);
// lambda
myAction = (int x, int y) =>
{
Debug.Log(x + " " + y);
};
myAction(3, 4);
}
}
UnityEvent
,有人说 Action/Func
直接用,之类的。