生活随笔
收集整理的這篇文章主要介紹了
Unity消息简易框架 Advanced C# messenger
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Unity消息簡易框架 Advanced C# messenger Unity ?
C# ?
消息機制 ?
【轉載 雨凇MOMO博客】 https://www.xuanyusong.com/archives/2165
Tips 在尋找Unity下好用的消息事件框架的時候無意中發現該框架,十分簡易,但又用起來特別方便。公司VR游戲中試了下,真滴方便。也不造輪子了,直接轉載雨凇大佬的博客,就當是Mark一下,方便以后學習。
正文 Advanced CSharp Messenger 屬于C#事件的一種。 維基百科中由詳細的說明http://wiki.unity3d.com/index.php?title=Advanced_CSharp_Messenger 上周的一天剛巧有朋友問到我這一塊的知識,那么我研究出來將它貼在博客中,幫助了他也幫助我自己!哇咔咔。
Advanced CSharp Messenger的特點可以將游戲對象做為參數發送。到底Advanced CSharp Messenger有什么用呢?先創建一個立方體對象,然后把Script腳本綁定在這個對象中。腳本中有一個方法叫DoSomething()。寫一段簡單的代碼,通常我們在調用方法的時候需要這樣來寫。
private Script script;? void Awake ( ) ? {? GameObject cube = GameObject.Find("Cube" );? script = cube.GetComponent<Script>();? }? ? void Update ( ) ? {? if (Input.GetMouseButtonDown(0 ))? {? script.DoSomething();? }? }? ? 代碼比較簡單,我就不注釋了。 原理就是先獲取游戲對象,接著獲取腳本組件對象,最后通過腳本組件對象去調用對應腳本中的方法,這樣的調用方法我們稱之為直接調用。
這個例子中我只調用了一個對象的方法,如果說有成千上萬個對象,那么這樣調用是不是感覺自己的代碼非常的丑?因為你需要一個一個的獲取對象然后獲取腳本組件然后在調用方法。。。。。 (想想都恐怖!!)
下面我們在用Advanced CSharp Messenger來實現事件的調用。按照維基百科中首先把Message.cs 和Callback.cs拷貝在你的工程中。
CallBack.cs
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()這樣就好比我們發送了一條廣播。
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自身也提供了一種發送消息的方法嗎?,用過的都知道效率也非常低下,雖然我們看不到它具體實現的源碼是如何實現的,但是我覺得原理可能也是這樣的。 歡迎和大家一起討論與學習。
轉載于:https://www.cnblogs.com/Firepad-magic/p/9484304.html
總結
以上是生活随笔 為你收集整理的Unity消息简易框架 Advanced C# messenger 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。