Unity消息簡易框架 Advanced C# messenger
Unity
C#
消息機制
【轉載 雨凇MOMO博客】 https://www.xuanyusong.com/archives/2165php
Tips
在尋找Unity下好用的消息事件框架的時候無心中發現該框架,十分簡易,但又用起來特別方便。公司VR遊戲中試了下,真滴方便。也不造輪子了,直接轉載雨凇大佬的博客,就當是Mark一下,方便之後學習。html
正文
Advanced CSharp Messenger 屬於C#事件的一種。 維基百科中由詳細的說明http://wiki.unity3d.com/index.php?title=Advanced_CSharp_Messenger 上週的一天剛巧有朋友問到我這一塊的知識,那麼我研究出來將它貼在博客中,幫助了他也幫助我本身!哇咔咔。框架
Advanced CSharp Messenger的特色能夠將遊戲對象作爲參數發送。到底Advanced CSharp Messenger有什麼用呢?先建立一個立方體對象,而後把Script腳本綁定在這個對象中。腳本中有一個方法叫DoSomething()。寫一段簡單的代碼,一般咱們在調用方法的時候須要這樣來寫。less
- private Script script;
- void Awake()
- {
- GameObject cube = GameObject.Find("Cube");
- script = cube.GetComponent<Script>();
- }
-
- void Update()
- {
- if(Input.GetMouseButtonDown(0))
- {
- script.DoSomething();
- }
- }
-
代碼比較簡單,我就不註釋了。 原理就是先獲取遊戲對象,接着獲取腳本組件對象,最後經過腳本組件對象去調用對應腳本中的方法,這樣的調用方法咱們稱之爲直接調用。學習
這個例子中我只調用了一個對象的方法,若是說有成千上萬個對象,那麼這樣調用是否是感受本身的代碼很是的醜?由於你須要一個一個的獲取對象而後獲取腳本組件而後在調用方法。。。。。 (想一想都恐怖!!)this
下面咱們在用Advanced CSharp Messenger來實現事件的調用。按照維基百科中首先把Message.cs 和Callback.cs拷貝在你的工程中。spa
CallBack.cs3d
- public delegate void Callback();
- public delegate void Callback<T>(T arg1);
- public delegate void Callback<T, U>(T arg1, U arg2);
- public delegate void Callback<T, U, V>(T arg1, U arg2, V arg3);
Message.cs代理
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #define REQUIRE_LISTENER
-
- using System;
- using System.Collections.Generic;
- using UnityEngine;
-
- static internal class Messenger {
- #region Internal variables
-
-
- #pragma warning disable 0414
-
- static private MessengerHelper messengerHelper = ( new GameObject("MessengerHelper") ).AddComponent< MessengerHelper >();
- #pragma warning restore 0414
-
- static public Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
-
-
- static public List< string > permanentMessages = new List< string > ();
- #endregion
- #region Helper methods
-
- static public void MarkAsPermanent(string eventType) {
- #if LOG_ALL_MESSAGES
- Debug.Log("Messenger MarkAsPermanent \t\"" + eventType + "\"");
- #endif
-
- permanentMessages.Add( eventType );
- }
-
- static public void Cleanup()
- {
- #if LOG_ALL_MESSAGES
- Debug.Log("MESSENGER Cleanup. Make sure that none of necessary listeners are removed.");
- #endif
-
- List< string > messagesToRemove = new List<string>();
-
- foreach (KeyValuePair<string, Delegate> pair in eventTable) {
- bool wasFound = false;
-
- foreach (string message in permanentMessages) {
- if (pair.Key == message) {
- wasFound = true;
- break;
- }
- }
-
- if (!wasFound)
- messagesToRemove.Add( pair.Key );
- }
-
- foreach (string message in messagesToRemove) {
- eventTable.Remove( message );
- }
- }
-
- static public void PrintEventTable()
- {
- Debug.Log("\t\t\t=== MESSENGER PrintEventTable ===");
-
- foreach (KeyValuePair<string, Delegate> pair in eventTable) {
- Debug.Log("\t\t\t" + pair.Key + "\t\t" + pair.Value);
- }
-
- Debug.Log("\n");
- }
- #endregion
-
- #region Message logging and exception throwing
- static public void OnListenerAdding(string eventType, Delegate listenerBeingAdded) {
- #if LOG_ALL_MESSAGES || LOG_ADD_LISTENER
- Debug.Log("MESSENGER OnListenerAdding \t\"" + eventType + "\"\t{" + listenerBeingAdded.Target + " -> " + listenerBeingAdded.Method + "}");
- #endif
-
- if (!eventTable.ContainsKey(eventType)) {
- eventTable.Add(eventType, null );
- }
-
- Delegate d = eventTable[eventType];
- if (d != null && d.GetType() != listenerBeingAdded.GetType()) {
- throw new ListenerException(string.Format("Attempting to add listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being added has type {2}", eventType, d.GetType().Name, listenerBeingAdded.GetType().Name));
- }
- }
-
- static public void OnListenerRemoving(string eventType, Delegate listenerBeingRemoved) {
- #if LOG_ALL_MESSAGES
- Debug.Log("MESSENGER OnListenerRemoving \t\"" + eventType + "\"\t{" + listenerBeingRemoved.Target + " -> " + listenerBeingRemoved.Method + "}");
- #endif
-
- if (eventTable.ContainsKey(eventType)) {
- Delegate d = eventTable[eventType];
-
- if (d == null) {
- throw new ListenerException(string.Format("Attempting to remove listener with for event type \"{0}\" but current listener is null.", eventType));
- } else if (d.GetType() != listenerBeingRemoved.GetType()) {
- throw new ListenerException(string.Format("Attempting to remove listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being removed has type {2}", eventType, d.GetType().Name, listenerBeingRemoved.GetType().Name));
- }
- } else {
- throw new ListenerException(string.Format("Attempting to remove listener for type \"{0}\" but Messenger doesn't know about this event type.", eventType));
- }
- }
-
- static public void OnListenerRemoved(string eventType) {
- if (eventTable[eventType] == null) {
- eventTable.Remove(eventType);
- }
- }
-
- static public void OnBroadcasting(string eventType) {
- #if REQUIRE_LISTENER
- if (!eventTable.ContainsKey(eventType)) {
- throw new BroadcastException(string.Format("Broadcasting message \"{0}\" but no listener found. Try marking the message with Messenger.MarkAsPermanent.", eventType));
- }
- #endif
- }
-
- static public BroadcastException CreateBroadcastSignatureException(string eventType) {
- return new BroadcastException(string.Format("Broadcasting message \"{0}\" but listeners have a different signature than the broadcaster.", eventType));
- }
-
- public class BroadcastException : Exception {
- public BroadcastException(string msg)
- : base(msg) {
- }
- }
-
- public class ListenerException : Exception {
- public ListenerException(string msg)
- : base(msg) {
- }
- }
- #endregion
-
- #region AddListener
-
- static public void AddListener(string eventType, Callback handler) {
- OnListenerAdding(eventType, handler);
- eventTable[eventType] = (Callback)eventTable[eventType] + handler;
- }
-
-
- static public void AddListener<T>(string eventType, Callback<T> handler) {
- OnListenerAdding(eventType, handler);
- eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler;
- }
-
-
- static public void AddListener<T, U>(string eventType, Callback<T, U> handler) {
- OnListenerAdding(eventType, handler);
- eventTable[eventType] = (Callback<T, U>)eventTable[eventType] + handler;
- }
-
-
- static public void AddListener<T, U, V>(string eventType, Callback<T, U, V> handler) {
- OnListenerAdding(eventType, handler);
- eventTable[eventType] = (Callback<T, U, V>)eventTable[eventType] + handler;
- }
- #endregion
-
- #region RemoveListener
-
- static public void RemoveListener(string eventType, Callback handler) {
- OnListenerRemoving(eventType, handler);
- eventTable[eventType] = (Callback)eventTable[eventType] - handler;
- OnListenerRemoved(eventType);
- }
-
-
- static public void RemoveListener<T>(string eventType, Callback<T> handler) {
- OnListenerRemoving(eventType, handler);
- eventTable[eventType] = (Callback<T>)eventTable[eventType] - handler;
- OnListenerRemoved(eventType);
- }
-
-
- static public void RemoveListener<T, U>(string eventType, Callback<T, U> handler) {
- OnListenerRemoving(eventType, handler);
- eventTable[eventType] = (Callback<T, U>)eventTable[eventType] - handler;
- OnListenerRemoved(eventType);
- }
-
-
- static public void RemoveListener<T, U, V>(string eventType, Callback<T, U, V> handler) {
- OnListenerRemoving(eventType, handler);
- eventTable[eventType] = (Callback<T, U, V>)eventTable[eventType] - handler;
- OnListenerRemoved(eventType);
- }
- #endregion
-
- #region Broadcast
-
- static public void Broadcast(string eventType) {
- #if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
- Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
- #endif
- OnBroadcasting(eventType);
-
- Delegate d;
- if (eventTable.TryGetValue(eventType, out d)) {
- Callback callback = d as Callback;
-
- if (callback != null) {
- callback();
- } else {
- throw CreateBroadcastSignatureException(eventType);
- }
- }
- }
-
-
- static public void Broadcast<T>(string eventType, T arg1) {
- #if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
- Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
- #endif
- OnBroadcasting(eventType);
-
- Delegate d;
- if (eventTable.TryGetValue(eventType, out d)) {
- Callback<T> callback = d as Callback<T>;
-
- if (callback != null) {
- callback(arg1);
- } else {
- throw CreateBroadcastSignatureException(eventType);
- }
- }
- }
-
-
- static public void Broadcast<T, U>(string eventType, T arg1, U arg2) {
- #if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
- Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
- #endif
- OnBroadcasting(eventType);
-
- Delegate d;
- if (eventTable.TryGetValue(eventType, out d)) {
- Callback<T, U> callback = d as Callback<T, U>;
-
- if (callback != null) {
- callback(arg1, arg2);
- } else {
- throw CreateBroadcastSignatureException(eventType);
- }
- }
- }
-
-
- static public void Broadcast<T, U, V>(string eventType, T arg1, U arg2, V arg3) {
- #if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
- Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
- #endif
- OnBroadcasting(eventType);
-
- Delegate d;
- if (eventTable.TryGetValue(eventType, out d)) {
- Callback<T, U, V> callback = d as Callback<T, U, V>;
-
- if (callback != null) {
- callback(arg1, arg2, arg3);
- } else {
- throw CreateBroadcastSignatureException(eventType);
- }
- }
- }
- #endregion
- }
-
-
- public sealed class MessengerHelper : MonoBehaviour {
- void Awake ()
- {
- DontDestroyOnLoad(gameObject);
- }
-
-
- public void OnDisable() {
- Messenger.Cleanup();
- }
- }
而後就能夠開始使用了,Messager.Broadcast()這樣就比如咱們發送了一條廣播。rest
- void Update()
- {
- if(Input.GetMouseButtonDown(0))
- {
- Messenger.Broadcast("Send");
- }
- }
在須要這條廣播的類中來接受它,一樣是剛剛說的Script類。接受廣播的標誌是 Messager.AddListener()參數1表示廣播的名稱,參數2表示廣播所調用的方法。
- using UnityEngine;
- using System.Collections;
-
- public class Script : MonoBehaviour {
-
- void Awake()
- {
- Messenger.AddListener( "Send", DoSomething );
- }
- public void DoSomething()
- {
- Debug.Log("DoSomething");
- }
- }
這樣一來,只要發送名稱爲」Send」的方法,就能夠在別的類中接收它了。
咱們在說說如何經過廣播來傳遞參數,這也是那天那個哥們主要問個人問題。(實際上是維基百科上寫的不是特別特別的清楚,那哥們誤解了)在Callback中能夠看出參數最多能夠是三個,參數的類型是任意類型,也就是說咱們不只能傳遞 int float bool 還能傳遞gameObject類型。
以下所示,發送廣播的時候傳遞了兩個參數,參數1是一個遊戲對象,參數2是一個int數值。
- void Update()
- {
- if(Input.GetMouseButtonDown(0))
- {
- GameObject cube = GameObject.Find("Cube");
- Messenger.Broadcast<GameObject,int>("Send",cube,1980);
- }
- }
而後是接受的地方 參數用<>存在一塊兒。遊戲對象也能夠完美的傳遞。
- using UnityEngine;
- using System.Collections;
-
- public class Script : MonoBehaviour {
-
- void Awake()
- {
- Messenger.AddListener<GameObject,int>( "Send", DoSomething );
- }
- public void DoSomething(GameObject obj,int i)
- {
- Debug.Log("name " + obj.name + " id =" + i);
- }
- }
若是傳遞一個參數
兩個參數<T,T>
三個參數<T,T,T>
怎麼樣使用起來仍是挺簡單的吧?
我以爲項目中最好不要大量的使用代理事件這類的方法(根據需求而定),雖然可讓你的代碼很是的簡潔,可是它的效率不高大概比直接調用慢5-倍左右吧,就比如美好的東西必定都有瑕疵同樣。 還記得Unity自身也提供了一種發送消息的方法嗎?,用過的都知道效率也很是低下,雖然咱們看不到它具體實現的源碼是如何實現的,可是我以爲原理可能也是這樣的。 歡迎和你們一塊兒討論與學習。