目录
前言:
一、定义事件基础类
二、定义事件资源类
三、定义事件管理类
四、事件使用实例
在Unity游戏开发中,事件系统非常重要,主要原因有以下几点:
松耦合:通过事件系统,我们可以实现代码的松耦合,这意味着我们可以将代码中的类解耦。在游戏开发中,如果代码是紧耦合的,当代码量增大时,很容易导致代码混乱难以维护。事件系统的松耦合可以减小这种压力,可以更好地组合和管理游戏对象。
效率高:使用事件系统可以让游戏对象通过广播自己的状态,而不需要每个游戏对象都去检测其他对象的状态,这可以对性能产生显着影响,从而提高游戏效率。
易扩展:当游戏需要新的功能时,通过事件系统,我们可以很容易地扩展代码,只需创造新的事件,并让其他代码订阅新事件即可,而不必改变原有代码。
总之,使用事件系统可以帮助我们设计和管理游戏对象,增加代码的可读性和可维护性,同时也可以提高游戏运行效率和可扩展性。在Unity游戏开发中,事件系统可以说是不可或缺的一部分。
public class UEvent
{
public readonly int type;
public UEvent(int eventType)
{
this.type = eventType;
}
public static T New() where T: UEvent, IPoolItem,new()
{
return Engine.Pools.Pop();
}
}
事件资源类是真正处理事件的内部类,它有三个重要的接口
TriggerEvent 触发相应事件
订阅Subscribe相应事件
取消订阅Unsubscribe相应事件
using System;
using System.Collections.Generic;
internal class UEventSource where T : UEvent
{
private readonly Dictionary>> events = new Dictionary>>();
internal void TriggerEvent(T value)
{
var key = value.type;
if (!events.TryGetValue(key, out List> outList))
return;
for (var i = 0; i < outList.Count; i++)
{
outList[i]?.Invoke(value);
}
}
internal void Subscribe(int type, Action handler)
{
if (events.ContainsKey(type))
{
List> list = events[type];
if (list == null)
{
list = new List>();
events[type] = list;
}
#if UNITY_EDITOR
if (list.Contains(handler))
{
ULog.Warn("重复注册事件 {0} {1}", type, handler);
return;
}
#endif
list.Add(handler);
}
else
{
List> list = new List> {handler};
events[type] = list;
}
}
internal void Unsubscribe(int type, Action handler)
{
if (events.ContainsKey(type))
{
List> list = events[type];
if (list != null)
{
list.Remove(handler);
}
}
}
internal void Destroy()
{
events.Clear();
}
事件管理类是对外操作类,它提供了异步触发和立即触发功能,包含总要的几个接口:
订阅事件接口
public void Subscribe(int type, Action handler)
取消订阅接口
public void Unsubscribe(int type, Action handler)
立即触发接口
private void TriggerEventImmediate(UEvent value)
发送事件
public void SendMessage(UEvent value, bool isImmediate=true)
isImmediate表示是否立刻触发,否则等下帧触发
事件管理类完整代码
using System;
using System.Collections.Generic;
public class EventsComponent
{
private readonly HashSet firingTypes = new HashSet();
private readonly UEventSource source = new UEventSource();
private readonly List tickEvents = new List();
public void SendMessage(UEvent value, bool isImmediate=true)
{
if (isImmediate)
{
TriggerEventImmediate(value);
return;
}
tickEvents.Add(value);
}
public void Update()
{
if (tickEvents.Count == 0)
return;
foreach (var t in tickEvents)
{
TriggerEventImmediate(t);
}
tickEvents.Clear();
}
public void Subscribe(int type, Action handler)
{
source.Subscribe(type, handler);
}
public void Unsubscribe(int type, Action handler)
{
source.Unsubscribe(type, handler);
}
public void Destroy()
{
tickEvents.Clear();
firingTypes.Clear();
source.Destroy();
}
private void TriggerEventImmediate(UEvent value)
{
firingTypes.Add(value.type);
source.TriggerEvent(value);
firingTypes.Remove(value.type);
}
}
在一个关卡中,游戏角色死亡作为我们判定结果的一个唯一条件,我们希望该角色死亡就触发结果,就以此为例写一个简单实例。
定义事件类型
public class EventLogicCode
{
public const int Dead = 1;
}
定义死亡事件
///
/// 死亡事件
///
public class EventDead : UEvent
{
public int _actorId;
public EventDead() : base(EventLogicCode.Dead)
{
}
}
角色类代码如下
public class Charactor
{
private EventsComponent _events; //记得给事件组件赋值
private int _id;
....
//角色死亡调用
public void Dead()
{
EventDead dead = new EventDead();
dead.id = id;
_events?.SendMesage(dead);
}
}
结果控制类
public class ResultController : MonoBehaviour
{
private EventsComponent _events;//记得赋值
private int _winId;
.....
private void OnEnable()
{
_events?.Subscribe(EventLogicCode.Dead, BeginFade);
}
private void OnDisable()
{
_events?.Unsubscribe(EventLogicCode.Dead, BeginFade);
}
public void OnDead(UEvent e)
{
EventDead dead = e as EventDead;
if(dead.id == _winId)
{
GameWin();
}
}
private void GameWin()
{
....
}
}
该类描述的是当角色死亡时判定是不是与胜利条件相同的Id,如果是,那么就胜利了