1. 程式人生 > >unity利用事件機制解耦程式碼(四)

unity利用事件機制解耦程式碼(四)

在某一個類呼叫另一個類裡的方法的時候,往往需要這個類的例項,這在繁複的專案中,往往沒有那麼方便,需要在這個類中不斷的通過物件圖語言導航到我們需要的地方。但如果使用事件機制的,在這個類裡發起一個事件,在另一個類了處理這個事件,就可以不需要這個例項物件,就能完成。

這裡有兩杯水,怎樣將這兩個杯子裡的水調換一下呢?你需要第三隻空杯子。事件機制,說實話也是這個道理,當你找到第三隻杯子的時候,你就會覺得,沒有什麼難的了。

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,"測試");
    }

}
 由於我自己專案的關係,這個事件機制,能做到同一幀發起一次,處理多次的事件;同一幀多次發起同一個事件,多次發起的話只會執行最後一次發起。
如果你想請我喝杯咖啡,就掃下面的圖片吧