Unity フロントエンド アーキテクチャのイベント システムの完全なコード実装

目次

序文:

1. イベント基本クラスを定義する

2. イベントリソースクラスを定義する

3. イベント管理クラスを定義する

4. イベント利用例


序文:

Unity のゲーム開発においてイベントシステムは非常に重要ですが、その主な理由は次のとおりです。

  1. 疎結合: イベント システムを通じて、コードの疎結合を実現できます。これは、コード内のクラスを分離できることを意味します。ゲーム開発において、コードが密結合している場合、コード量が増加するとコードの混乱やメンテナンスの困難が発生しやすくなります。イベント システムの疎結合により、このプレッシャーが軽減され、ゲーム オブジェクトのより適切な構成と管理が可能になります。

  2. 高効率: イベント システムを使用すると、各ゲーム オブジェクトが他のオブジェクトの状態を検出する必要がなく、ゲーム オブジェクトが独自の状態をブロードキャストできるため、パフォーマンスに大きな影響を与え、ゲーム効率を向上させることができます。

  3. 拡張が簡単: ゲームに新しい機能が必要な場合は、元のコードを変更せずに、イベント システムを通じてコードを簡単に拡張できます。新しいイベントを作成し、他のコードが新しいイベントをサブスクライブできるようにするだけです。

つまり、イベント システムを使用すると、ゲーム オブジェクトの設計と管理が容易になり、コードの可読性と保守性が向上し、ゲームの効率とスケーラビリティも向上します。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 が同じかどうかを記述し、同じであれば勝利となります。

 


おすすめ

転載: blog.csdn.net/lejian/article/details/131275445