unity利用事件機制解耦程式碼(四)
阿新 • • 發佈:2018-12-30
在某一個類呼叫另一個類裡的方法的時候,往往需要這個類的例項,這在繁複的專案中,往往沒有那麼方便,需要在這個類中不斷的通過物件圖語言導航到我們需要的地方。但如果使用事件機制的,在這個類裡發起一個事件,在另一個類了處理這個事件,就可以不需要這個例項物件,就能完成。
這裡有兩杯水,怎樣將這兩個杯子裡的水調換一下呢?你需要第三隻空杯子。事件機制,說實話也是這個道理,當你找到第三隻杯子的時候,你就會覺得,沒有什麼難的了。
上面這個類就是第三隻杯子。using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using Object = System.Object; public class EventManager : MonoBehaviour { private static EventManager _instance; /// <summary> /// 發起事件的字典 /// </summary> private readonly Dictionary<string, System.Object> _dicIssue = new Dictionary<string, Object>(); /// <summary> /// 處理事件的字典 /// </summary> private Dictionary<string, List<Action<Object>>> _handleDictionary = new Dictionary<string, List<Action<object>>>(); /// <summary> /// 單例 /// </summary> /// <returns></returns> public static EventManager GetInstance() { if (_instance == null) { var go = GameObject.Find("game"); if (go == null) { go = new GameObject("game"); } var eventManager = go.GetComponent<EventManager>(); if (eventManager == null) { eventManager = go.AddComponent<EventManager>(); } _instance = eventManager; DontDestroyOnLoad(go); } return _instance; } /// <summary> /// 發起一個事件鼓勵在eventname裡面新增新的列舉,便於查詢所有引用 /// </summary> /// <param name="eventName"></param> /// <param name="data"></param> public void IssueEvent(string eventName, Object data) { if (_dicIssue.ContainsKey(eventName)) { _dicIssue[eventName] = data; } else { _dicIssue.Add(eventName, data); } } /// <summary> /// 發起一個事件,鼓勵在eventname裡面新增新的列舉,便於查詢所有引用 /// </summary> /// <param name="name"></param> /// <param name="data"></param> public void IssueEvent(EventName name, Object data) { IssueEvent(name.ToString(), data); } List<Action<Object>> _eventList = new List<Action<Object>>(); /// <summary> /// 處理這個事件鼓勵在eventname裡面新增新的列舉,便於查詢所有引用 /// </summary> /// <param name="eventName"></param> /// <param name="action"></param> public void HandleEvent(string eventName, Action<Object> action) { if (!_handleDictionary.ContainsKey(eventName)) { _eventList.Clear(); _handleDictionary.Add(eventName, _eventList); } _eventList = _handleDictionary[eventName]; _eventList.Add(action); _handleDictionary[eventName] = _eventList; } /// <summary> /// 處理這個事件鼓勵在eventname裡面新增新的列舉,便於查詢所有引用 /// </summary> /// <param name="name"></param> /// <param name="action"></param> public void HandleEvent(EventName name, Action<Object> action) { HandleEvent(name.ToString(), action); } private void Update() { if (_dicIssue.Count > 0) { foreach (var key in _dicIssue.Keys) { if (_handleDictionary.ContainsKey(key)) { var count = _handleDictionary[key].Count; if (count > 0) { for (int i = 0; i < count; i++) { try { _handleDictionary[key][i](_dicIssue[key]); } catch (Exception e) { Debug.LogError(key+"方法出錯啦,錯誤是:"+ e.ToString()); } } } } } _dicIssue.Clear(); } } }
下面是對他的使用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public enum EventName
{
/// <summary>
/// 測試事件機制
/// </summary>
testEvent
}
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Test1 : MonoBehaviour { // Use this for initialization void Start () { EventManager.GetInstance().HandleEvent(EventName.testEvent, (o) => { Debug.LogError("Test1裡的"+o.ToString()); }); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Test2 : MonoBehaviour { // Use this for initialization void Start () { EventManager.GetInstance().HandleEvent(EventName.testEvent, (o) => { Debug.LogError("Test2裡的" + o.ToString()); }); } }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test3 : MonoBehaviour {
// Use this for initialization
void Start ()
{
StartCoroutine(test());
}
IEnumerator test()
{
yield return new WaitForSeconds(5);
EventManager.GetInstance().IssueEvent(EventName.testEvent,"測試");
}
}
由於我自己專案的關係,這個事件機制,能做到同一幀發起一次,處理多次的事件;同一幀多次發起同一個事件,多次發起的話只會執行最後一次發起。如果你想請我喝杯咖啡,就掃下面的圖片吧