特别提示: 本系列基于Unity 2019.4.8,框架版本GameFramework 2021.05.31
本系列博客地址: 传送门
Game Framework 支持在游戏逻辑监听、抛出事件。其中很多模块在完成操作后都会抛出内置事件,监听这些事件将大大解除游戏逻辑之间的耦合。除了 Game Framework 内置事件外,使用者也可以定义自己的游戏逻辑事件,游戏中所有事件均派生自 GameEventArgs 类,事件对象使用了引用池技术,以避免使用事件过程中频繁的内存分配。
对事件还不熟的先自行去补基础, Game Framework 内置事件都已经写好了直接使用就行了,这里讲讲怎么使用自定义事件
一、创建自定义事件
所有的事件都继承GameEventArgs 类,变量跟方法可以随意定义,但是最少包含Id和Clear()方法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GameFramework.Event;
using GameFramework;
public class KeyCodePressEventArgs : GameEventArgs
{
public static readonly int EventId = typeof(KeyCodePressEventArgs).GetHashCode();
public override int Id
{
get { return EventId; }
}
public KeyCode KeyCode
{
get;
private set;
}
public KeyCodePressEventArgs()
{
KeyCode = KeyCode.None;
}
public static KeyCodePressEventArgs Create(KeyCode keyCode)
{
// 使用引用池技术,避免频繁内存分配
KeyCodePressEventArgs keyCodePressEventArgs = ReferencePool.Acquire<KeyCodePressEventArgs>();
keyCodePressEventArgs.KeyCode = keyCode;
return keyCodePressEventArgs;
}
public override void Clear()
{
// 使用引用池技术,注意清理事件实例数据
KeyCode = KeyCode.None;
}
}
二、订阅自定义事件
可以写在任意地方只要逻辑没有错误
官方建议定义一个EventHandler,来降低将方法转换为 EventHandler 时的内存开销
EventHandler<GameEventArgs> KeyCodePressEventHandler;
KeyCodePressEventHandler = KeyCodePress;
eventComponent.Subscribe(KeyCodePressEventArgs.EventId, KeyCodePressEventHandler);
eventComponent.Unsubscribe(KeyCodePressEventArgs.EventId, KeyCodePressEventHandler);
三、抛出事件
达到特定条件抛出事件,执行所有订阅此事件的回调函数
四、取消订阅
事件的订阅与取消订阅在使用生命周期内,应当成对出现。Game Framework 会严格检查事件订阅的匹配情况,不允许出现重复订阅,也不允许出现重复取消订阅或取消订阅尚未订阅的事件处理函数,如果出现这些情况,将会抛出异常。
五、常见问题
1、错误地缓存了事件实例
事件处理函数处理事件时,不应该缓存 GameEventArgs 实例,GameEventArgs 实例的有效生命周期,仅限于事件处理函数内。Game Framework 为了降低内存分配,事件实例使用了引用池技术。一个事件被其所有事件处理函数处理完成后,事件实例会被立刻清理并回收(调用 GameEventArgs 中的 Clear 方法)。后续逻辑访问缓存的事件实例时,将无法访问到任何有效数据。因此,缓存事件实例是完全错误的,这将导致难以追踪的 BUG。
//这是错误的示例!
KeyCodePressEventArgs keyCodePressEventArgs=null;
void KeyCodePress(object sender, GameEventArgs e)
{
keyCodePressEventArgs = (KeyCodePressEventArgs)e;
Log.Error($"{keyCodePressEventArgs.KeyCode}被按下");
}
2、自定义事件类的 Clear 方法实现不完整
自定义事件类使用了引用池技术,事件实例是会被复用的。当回收某个事件实例时,不完整的 Clear 实现无法清理干净事件实例中的数据,进而将脏数据带到下一次复用事件实例的逻辑中去,这可能导致难以追踪的 BUG。
3、事件模块不工作
事件模块需要被轮询才能正常调用事件处理函数,请确认正确初始化了 Game Framework。