目次
序文:
Unity のゲーム開発においてイベントシステムは非常に重要ですが、その主な理由は次のとおりです。
-
疎結合: イベント システムを通じて、コードの疎結合を実現できます。これは、コード内のクラスを分離できることを意味します。ゲーム開発において、コードが密結合している場合、コード量が増加するとコードの混乱やメンテナンスの困難が発生しやすくなります。イベント システムの疎結合により、このプレッシャーが軽減され、ゲーム オブジェクトのより適切な構成と管理が可能になります。
-
高効率: イベント システムを使用すると、各ゲーム オブジェクトが他のオブジェクトの状態を検出する必要がなく、ゲーム オブジェクトが独自の状態をブロードキャストできるため、パフォーマンスに大きな影響を与え、ゲーム効率を向上させることができます。
-
拡張が簡単: ゲームに新しい機能が必要な場合は、元のコードを変更せずに、イベント システムを通じてコードを簡単に拡張できます。新しいイベントを作成し、他のコードが新しいイベントをサブスクライブできるようにするだけです。
つまり、イベント システムを使用すると、ゲーム オブジェクトの設計と管理が容易になり、コードの可読性と保守性が向上し、ゲームの効率とスケーラビリティも向上します。Unityのゲーム開発において、イベントシステムは欠かせない部分と言えます。
1. イベント基本クラスを定義する
public class UEvent
{
public readonly int type;
public UEvent(int eventType)
{
this.type = eventType;
}
public static T New<T>() where T: UEvent, IPoolItem,new()
{
return Engine.Pools.Pop<T>();
}
}
2. イベントリソースクラスを定義する
イベント リソース クラスは、実際にイベントを処理する内部クラスであり、3 つの重要なインターフェイスがあります。
TriggerEvent は対応するイベントをトリガーします
対応するイベントを購読する
登録解除 対応するイベントの登録解除
using System;
using System.Collections.Generic;
internal class UEventSource<T> where T : UEvent
{
private readonly Dictionary<int, List<Action<T>>> events = new Dictionary<int, List<Action<T>>>();
internal void TriggerEvent(T value)
{
var key = value.type;
if (!events.TryGetValue(key, out List<Action<T>> outList))
return;
for (var i = 0; i < outList.Count; i++)
{
outList[i]?.Invoke(value);
}
}
internal void Subscribe(int type, Action<T> handler)
{
if (events.ContainsKey(type))
{
List<Action<T>> list = events[type];
if (list == null)
{
list = new List<Action<T>>();
events[type] = list;
}
#if UNITY_EDITOR
if (list.Contains(handler))
{
ULog.Warn("重复注册事件 {0} {1}", type, handler);
return;
}
#endif
list.Add(handler);
}
else
{
List<Action<T>> list = new List<Action<T>> {handler};
events[type] = list;
}
}
internal void Unsubscribe(int type, Action<T> handler)
{
if (events.ContainsKey(type))
{
List<Action<T>> list = events[type];
if (list != null)
{
list.Remove(handler);
}
}
}
internal void Destroy()
{
events.Clear();
}
3. イベント管理クラスを定義する
イベント管理クラスは外部操作クラスであり、次のいくつかのインターフェイスを含む非同期トリガー機能と即時トリガー機能を提供します。
サブスクライブイベントインターフェース
public void Subscribe(int type, Action<UEvent> handler)
購読解除インターフェイス
public void Unsubscribe(int type, Action<UEvent> 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<int> firingTypes = new HashSet<int>();
private readonly UEventSource<UEvent> source = new UEventSource<UEvent>();
private readonly List<UEvent> tickEvents = new List<UEvent>();
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<UEvent> handler)
{
source.Subscribe(type, handler);
}
public void Unsubscribe(int type, Action<UEvent> 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);
}
}
4. イベント利用例
レベルでは、ゲーム キャラクターの死が結果を決定する唯一の条件です。キャラクターの死が結果のトリガーになることを願っています。これを例として、簡単な例を書いてみましょう。
イベントタイプの定義
public class EventLogicCode
{
public const int Dead = 1;
}
死亡イベントを定義する
/// <summary>
/// 死亡事件
/// </summary>
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 が同じかどうかを記述し、同じであれば勝利となります。