您的位置:首页 > 移动开发 > Unity3D

unity中事件分发系统 EventDispatcher

2015-03-22 14:40 309 查看
出处:http://blog.csdn.net/u010019717
author:孙广东 时间:2015.3.21 23:00
不使用C#中的event关键字: 只是使用delegate和hashtable 进行事件的分发。
基本库如下:
namespace EventDispatcher
{
	/// <summary>
	/// IEvent接口
	/// </summary>
	public interface IEvent
	{
		/// <summary>
		/// Gets or sets the type.
		/// </summary>
		/// <value>
		/// type类型.
		/// </value>
		string type { get; set;}     
		
		/// <summary>
		/// Gets or sets the target.
		/// </summary>
		/// <value>
		/// target目标.
		/// </value>
		object target { get; set; }
	}
}
namespace EventDispatcher
{
	/// <summary>
	/// 事件事件接口
	/// </summary>
	public class Event : IEvent
	{
		// GETTER / SETTER
		/// <summary>
		/// The _type_string.
		/// </summary>
		private string _type_string;
		string IEvent.type { 
			get
			{
				return _type_string;
			}
			set
			{
				_type_string = value;
				
			}
		}
		
		/// <summary>
		/// The _target_object.
		/// </summary>
		private object _target_object;
		object IEvent.target { 
			get
			{
				return _target_object;
			}
			set
			{
				_target_object = value;
				
			}
		}

		///<summary>
		///	 Constructor
		///</summary>
		public Event (string aType_str )
		{
			//
			_type_string = aType_str;
		}

	    /// <summary>
	    /// Deconstructor
	    /// </summary>
	    //~Event ( )
	    //{
	    //	Debug.Log ("Event.deconstructor()");
	    //}
	}
}
namespace EventDispatcher
{
	/// <summary>
	/// IEventDispatcher 事件分发接口,添加移除分发
	/// </summary>
	public interface IEventDispatcher
	{
		/// <summary>
		/// 添加事件监听
		/// </summary>
		/// <returns><c>true</c>, 如果事件成功被监听, <c>false</c> 失败 </returns>
		/// <param name="aEventType_string">A event type_string.</param>
		/// <param name="aEventDelegate">一个事件委托</param>
	    bool addEventListener(string aEventType_string, EventDelegate aEventDelegate);

		/// <summary>
        /// 添加事件监听
		/// </summary>
        /// <returns><c>true</c>, 如果事件成功被监听, <c>false</c> 失败 </returns>
		/// <param name="aEventType_string">A event type_string.</param>
        /// <param name="aEventDelegate">一个事件委托</param>
		/// <param name="eventDispatcherAddMode">Event dispatcher add mode.</param>
		bool addEventListener(string aEventType_string, EventDelegate aEventDelegate, EventDispatcherAddMode eventDispatcherAddMode);

		/// <summary>
		/// 是否有这个事件监听
		/// </summary>
		/// <returns><c>true</c>, 这个监听已经有了, <c>false</c> 没有.</returns>
		/// <param name="aEventType_string">A event type_string.</param>
        /// <param name="aEventDelegate">一个事件委托</param>
	    bool hasEventListener(string aEventType_string, EventDelegate aEventDelegate);

		/// <summary>
		/// 移除事件监听
		/// </summary>
		/// <returns><c>true</c>, 被成功移除 <c>false</c> 失败</returns>
		/// <param name="aEventType_string">A event type_string.</param>
        /// <param name="aEventDelegate">一个事件委托</param>
	    bool removeEventListener(string aEventType_string, EventDelegate aEventDelegate);

		/// <summary>
        /// 移除所有事件监听
		/// </summary>
		/// <returns><c>true</c>, 成功, <c>false</c> 失败 </returns>
	    bool removeAllEventListeners();

		/// <summary>
		/// 分发广播事件
		/// </summary>
		/// <returns><c>true</c>, 成功, <c>false</c> 失败</returns>
		/// <param name="aIEvent">A I event.</param>
	    bool dispatchEvent(IEvent aIEvent);
	}
}
// C# unity事件管理器 在哈希表中使用字符串,对委托和事件管理 
// 不知道他们何时何地declared/defined 也允许使用事件。

using UnityEngine;
using System.Collections;

namespace EventDispatcher
{
	/// <summary>
    /// Event delegateN事件委托
	/// </summary>
    public delegate void EventDelegate ( IEvent iEvent );
	
	/// <summary>
	/// Event listening mode.
	/// </summary>
	public enum EventDispatcherAddMode
	{
		DEFAULT,
		SINGLE_SHOT
	}

	public class EventDispatcher : IEventDispatcher 
	{
		/// <summary>
		/// The mom_serialized object.
		/// </summary>
	    private Hashtable _eventListenerDatas_hashtable = new Hashtable();
	 
		/// <summary>
		/// The _target_object.
		/// </summary>
		private object _target_object;

		///<summary>
		///	 Constructor
		///</summary>
		public EventDispatcher (object aTarget_object )
		{
			//
			_target_object = aTarget_object;
		}
		
		/// <summary>
		/// Deconstructor
		/// </summary>
		//~EventDispatcher ( )
		//{
		//	Debug.Log ("EventDispatcher.deconstructor()");
			
		//}
		
		
		/// <summary>
		/// Adds the event listener.
		/// </summary>
		/// <returns>
		/// The event listener.
		/// </returns>
		/// <param name='aEventName_string'>
		/// If set to <c>true</c> a event name_string.
		/// </param>
		/// <param name='aEventDelegate'>
		/// If set to <c>true</c> a event delegate.
		/// </param>
	    public bool addEventListener(string aEventName_string, EventDelegate aEventDelegate)
	    {
			return addEventListener (aEventName_string, aEventDelegate, EventDispatcherAddMode.DEFAULT);	
		}
			
		/// <summary>
		/// Adds the event listener.
		/// </summary>
		/// <returns>
		/// The event listener.
		/// </returns>
		/// <param name='aEventName_string'>
		/// If set to <c>true</c> a event type_string.
		/// </param>
		/// <param name='aEventDelegate'>
		/// If set to <c>true</c> a event delegate.
		/// </param>
		/// <param name='aEventDispatcherAddMode'>
		/// If set to <c>true</c> event listening mode.
		/// </param>
	    public bool addEventListener(string aEventName_string, EventDelegate aEventDelegate, EventDispatcherAddMode aEventDispatcherAddMode)
	    {
			//
			bool wasSuccessful_boolean = false;
			
			//
			object aIEventListener = _getArgumentsCallee(aEventDelegate);			
			
			//
	        if (aIEventListener != null && aEventName_string != null) {
				
				//	OUTER
				string keyForOuterHashTable_string = _getKeyForOuterHashTable (aEventName_string);
		        if (!_eventListenerDatas_hashtable.ContainsKey(keyForOuterHashTable_string) ) {
		            _eventListenerDatas_hashtable.Add(keyForOuterHashTable_string, new Hashtable());
				}
		 
				//	INNER
		        Hashtable inner_hashtable = _eventListenerDatas_hashtable[keyForOuterHashTable_string] as Hashtable;
				EventListenerData eventListenerData = new EventListenerData (aIEventListener, aEventName_string, aEventDelegate, aEventDispatcherAddMode);
				//
				string keyForInnerHashTable_string = _getKeyForInnerHashTable (eventListenerData);
		        if (inner_hashtable.Contains(keyForInnerHashTable_string)) {
					
					//THIS SHOULD *NEVER* HAPPEN - REMOVE AFTER TESTED WELL
		            Debug.Log("TODO (FIX THIS): Event Manager: Listener: " + keyForInnerHashTable_string + " is already in list for event: " + keyForOuterHashTable_string);

				} else {
		 
					//	ADD
		        	inner_hashtable.Add(keyForInnerHashTable_string, eventListenerData);
					wasSuccessful_boolean = true;
					//Debug.Log ("	ADDED AT: " + keyForInnerHashTable_string + " = " +  eventListenerData);
				}
				
			}
	        return wasSuccessful_boolean;
	    }
		
		
	    /// <summary>
	    /// Hases the event listener.
	    /// </summary>
	    /// <returns>
	    /// The event listener.
	    /// </returns>
	    /// <param name='aIEventListener'>
	    /// If set to <c>true</c> a I event listener.
	    /// </param>
	    /// <param name='aEventName_string'>
	    /// If set to <c>true</c> a event name_string.
	    /// </param>
	    /// <param name='aEventDelegate'>
	    /// If set to <c>true</c> a event delegate.
	    /// </param>
	    public bool hasEventListener(string aEventName_string, EventDelegate aEventDelegate)
	    {
			//
			bool hasEventListener_boolean = false;
			
			//
			object aIEventListener = _getArgumentsCallee(aEventDelegate);			
			
			//	OUTER
			string keyForOuterHashTable_string = _getKeyForOuterHashTable (aEventName_string);
	        if (_eventListenerDatas_hashtable.ContainsKey(keyForOuterHashTable_string)) {
	        
				//	INNER
				Hashtable inner_hashtable = _eventListenerDatas_hashtable[keyForOuterHashTable_string] as Hashtable;
				string keyForInnerHashTable_string = _getKeyForInnerHashTable (new EventListenerData (aIEventListener, aEventName_string, aEventDelegate, EventDispatcherAddMode.DEFAULT));
				//
				if (inner_hashtable.Contains(keyForInnerHashTable_string)) {
		            hasEventListener_boolean = true;
				}
			}
	 
	        return hasEventListener_boolean;
	    }
		
	    /// <summary>
	    /// Removes the event listener.
	    /// </summary>
	    /// <returns>
	    /// The event listener.
	    /// </returns>
	    /// <param name='aIEventListener'>
	    /// If set to <c>true</c> a I event listener.
	    /// </param>
	    /// <param name='aEventName_string'>
	    /// If set to <c>true</c> a event name_string.
	    /// </param>
	    /// <param name='aEventDelegate'>
	    /// If set to <c>true</c> a event delegate.
	    /// </param>
	    public bool removeEventListener(string aEventName_string, EventDelegate aEventDelegate)
	    {
			//
			bool wasSuccessful_boolean = false;
			
			//
			if (hasEventListener (aEventName_string, aEventDelegate)) {
				//	OUTER
				string keyForOuterHashTable_string = _getKeyForOuterHashTable (aEventName_string);
				Hashtable inner_hashtable = _eventListenerDatas_hashtable[keyForOuterHashTable_string] as Hashtable;
				//
				object aIEventListener = _getArgumentsCallee(aEventDelegate);	
				//  INNER
				string keyForInnerHashTable_string = _getKeyForInnerHashTable (new EventListenerData (aIEventListener, aEventName_string, aEventDelegate, EventDispatcherAddMode.DEFAULT));
				inner_hashtable.Remove(keyForInnerHashTable_string);
	        	wasSuccessful_boolean = true;
			} 
			
			return wasSuccessful_boolean;
			
	    }
		
		/// <summary>
		/// Removes all event listeners.
		/// </summary>
		/// <returns>
		/// The all event listeners.
		/// </returns>
	    public bool removeAllEventListeners()
	    {
			//
			bool wasSuccessful_boolean = false;
			
			//TODO, IS IT A MEMORY LEAK TO JUST RE-CREATE THE TABLE? ARE THE INNER HASHTABLES LEAKING?
			_eventListenerDatas_hashtable = new Hashtable();
			
			return wasSuccessful_boolean;
	    }
		
	 
	    /// <summary>
	    /// Dispatchs the event.
	    /// </summary>
	    /// <returns>
	    /// The event.
	    /// </returns>
	    /// <param name='aIEvent'>
	    /// If set to <c>true</c> a I event.
	    /// </param>
	    public bool dispatchEvent(IEvent aIEvent)
	    {
			
			//
			bool wasSuccessful_boolean = false;
			
			//
			_doAddTargetValueToIEvent (aIEvent);
			
			//	OUTER
	        string keyForOuterHashTable_string = _getKeyForOuterHashTable (aIEvent.type);
			int dispatchedCount_int = 0;
	        if (_eventListenerDatas_hashtable.ContainsKey(keyForOuterHashTable_string)) {
	 
				//	INNER
				Hashtable inner_hashtable = _eventListenerDatas_hashtable[keyForOuterHashTable_string] as Hashtable;
				IEnumerator innerHashTable_ienumerator = inner_hashtable.GetEnumerator();
				DictionaryEntry dictionaryEntry;
				EventListenerData eventListenerData;
				ArrayList toBeRemoved_arraylist = new ArrayList ();
				//
		        while (innerHashTable_ienumerator.MoveNext()) {
					
					dictionaryEntry = (DictionaryEntry)innerHashTable_ienumerator.Current;
					eventListenerData = dictionaryEntry.Value as EventListenerData;
					
					//***DO THE DISPATCH***
					//Debug.Log ("DISPATCH : ");
					//Debug.Log ("	n    : " + eventListenerData.eventName );
					//Debug.Log ("	from : " + aIEvent.target );
					//Debug.Log ("	to   : " + eventListenerData.eventListener );
					//Debug.Log ("	del  : " + eventListenerData.eventDelegate + " " + (eventListenerData.eventDelegate as System.Delegate).Method.DeclaringType.Name + " " + (eventListenerData.eventDelegate as System.Delegate).Method.Name.ToString());
					eventListenerData.eventDelegate (aIEvent);
					
					
					//TODO - THIS IS PROBABLY FUNCTIONAL BUT NOT OPTIMIZED, MY APPROACH TO HOW/WHY SINGLE SHOTS ARE REMOVED
					//REMOVE IF ONESHOT
					if (eventListenerData.eventListeningMode == EventDispatcherAddMode.SINGLE_SHOT) {
						
						toBeRemoved_arraylist.Add (eventListenerData);
					}
					
					
					//MARK SUCCESS, BUT ALSO CONTINUE LOOPING TOO
					wasSuccessful_boolean = true;
					dispatchedCount_int++;
		        }
				
				
				//CLEANUP ANY ONE-SHOT, SINGLE-USE 
				EventListenerData toBeRemoved_eventlistenerdata;
				for (int count_int = toBeRemoved_arraylist.Count -1; count_int >= 0; count_int --) {
					toBeRemoved_eventlistenerdata = toBeRemoved_arraylist[count_int] as EventListenerData;
					removeEventListener (toBeRemoved_eventlistenerdata.eventName, toBeRemoved_eventlistenerdata.eventDelegate);
				}
	 
	        	
			}
			
			
			return wasSuccessful_boolean;
	    }
		
		/// <summary>
		/// _dos the add target value to I event.
		/// </summary>
		/// <param name='aIEvent'>
		/// A I event.
		/// </param>
		/// <exception cref='System.NotImplementedException'>
		/// Is thrown when a requested operation is not implemented for a given type.
		/// </exception>
		public void _doAddTargetValueToIEvent (IEvent aIEvent)
		{
			aIEvent.target = _target_object;
		}

	    public void OnApplicationQuit()
	    {
			//TODO, DO THIS CLEANUP HERE, OR OBLIGATE API-USER TO DO IT??
	        _eventListenerDatas_hashtable.Clear();
	    }
		
		
		private string _getKeyForOuterHashTable (string aEventName_string)
		{
			//SIMPLY USING THE EVENT NAME - METHOD USED HERE, IN CASE I WANT TO TWEAK THIS MORE...
			return aEventName_string;
		}
		
		private string _getKeyForInnerHashTable (EventListenerData aEventListenerData)
		{
			//VERY UNIQUE - NICE!
			return aEventListenerData.eventListener.GetType().FullName + "_" + aEventListenerData.eventListener.GetType().GUID + "_" + aEventListenerData.eventName + "_" + (aEventListenerData.eventDelegate as System.Delegate).Method.Name.ToString();
		
		}

		public object _getArgumentsCallee (EventDelegate aEventDelegate)
		{
			return (aEventDelegate as System.Delegate).Target;
		}
	}
}
namespace EventDispatcher
{
	/// <summary>
    /// EventListenerData
	/// </summary>
	public class EventListenerData
	{
		/// <summary>
		/// The _event listener.
		/// </summary>
		private object _eventListener;
		public object eventListener 
		{ 
			get
			{
				return _eventListener;
			}
			set
			{
				_eventListener = value;
				
			}
		}
		
		/// <summary>
		/// 事件名
		/// </summary>
		private string _eventName_string;
		public string eventName 
		{ 
			get
			{
				return _eventName_string;
			}
			set
			{
				_eventName_string = value;
				
			}
		}
		
		
		
		/// <summary>
		/// 事件委托
		/// </summary>
		private EventDelegate _eventDelegate;
		public EventDelegate eventDelegate 
		{ 
			get
			{
				return _eventDelegate;
			}
			set
			{
				_eventDelegate = value;
				
			}
		}
		
		private EventDispatcherAddMode _eventListeningMode;
		public EventDispatcherAddMode eventListeningMode 
		{ 
			get
			{
				return _eventListeningMode;
			}
			set
			{
				_eventListeningMode = value;
				
			}
		}

		///<summary>
		///	 Constructor
		///</summary>
		public EventListenerData (object aEventListener, string aEventName_string, EventDelegate aEventDelegate, EventDispatcherAddMode aEventListeningMode )
		{
			_eventListener 		= aEventListener;
			_eventName_string 	= aEventName_string;
			_eventDelegate		= aEventDelegate;
			_eventListeningMode	= aEventListeningMode;
		}
		
		/// <summary>
		/// Deconstructor
		/// </summary>
		//~EventListenerData ( )
		//{
			//Debug.Log ("EventListenerData.deconstructor()");
			
		//}
	}
}

使用的例子:新建两个游戏对象然后挂上脚本!
namespace EventDispatcher
{
	/// <summary>
	/// Test event.
	/// </summary>
	public class SampleEvent : Event
	{
		// GETTER / SETTER
		/// <summary>
		/// An example of event-specific data you can add in.
		/// </summary>
		private string _customValue_string;
		public string customValue 
		{
			get {
				return _customValue_string;
			}
			set {
				_customValue_string = value;
			}
		}

		/// <summary>
		/// The Event Type Name
		/// </summary>
		public static string SAMPLE_EVENT = "SAMPLE_EVENT";
		
		/// <summary>
		/// Initializes a new instance of the <see cref="com.rmc.projects.event_dispatcher.SampleEvent"/> class.
		/// </summary>
		/// <param name="aType_str">A type_str.</param>
		public SampleEvent (string aType_str ) : base (aType_str)
		{
			
		}
		
		/// <summary>
		/// Releases unmanaged resources and performs other cleanup operations before the
		/// <see cref="com.rmc.projects.event_dispatcher.SampleEvent"/> is reclaimed by garbage collection.
		/// </summary>
		//~SampleEvent ( )
		//{
		//	Debug.Log ("SampleEvent.deconstructor()");
		
		//}

	}
}
using UnityEngine;

namespace EventDispatcher
{
	public class SampleObservedComponent : MonoBehaviour 
	{
		/// <summary>
		/// The event dispatcher.
		/// </summary>
		public EventDispatcher eventDispatcher;

		/// <summary>
		/// Initializes a new instance of the <see cref="com.rmc.projects.event_dispatcher.SampleObservedComponent"/> class.
		/// </summary>
		public SampleObservedComponent ()
		{
			
			eventDispatcher = new EventDispatcher (this);
		}

		///<summary>
		///	Use this for initialization
		///</summary>
		public void Start () 
		{
			SampleEvent sampleEvent = new SampleEvent (SampleEvent.SAMPLE_EVENT);
			sampleEvent.customValue = "foo";
			Debug.Log ("Dispatching: SampleEvent " + sampleEvent);
			eventDispatcher.dispatchEvent (sampleEvent);
		}

		/// <summary>
		/// Raises the destroy event.
		/// </summary>
		public void OnDestroy ()
		{
			//	CLEANUP MEMORY
			eventDispatcher.removeAllEventListeners();
			eventDispatcher = null;
		}
	}
}
using UnityEngine;

namespace EventDispatcher
{
	public class SampleObserverComponent : MonoBehaviour 
	{
		/// <summary>
		/// The sample observed game object.
		/// </summary>
		public SampleObservedComponent sampleObservedGameObject;

		public void Start () 
		{
            /*
             * 注意: 这里observer和observed是 MonoBehavior 子类
             **/
            sampleObservedGameObject.eventDispatcher.addEventListener (SampleEvent.SAMPLE_EVENT, _onSampleEvent);
			
		}

		void Update () 
		{
			//Debug.Log (sampleObservedGameObject.eventDispatcher);
		}

		/// <summary>
		/// Raises the destroy event.
		/// </summary>
		public void OnDestroy ()
		{
			//	CLEANUP MEMORY
			sampleObservedGameObject.eventDispatcher.removeEventListener (SampleEvent.SAMPLE_EVENT, _onSampleEvent);
			
		}
		//--------------------------------------
		//  Events 
		//--------------------------------------
		/// <summary>
		/// _ons the sample event.
		/// </summary>
		/// <param name="aIEvent">A I event.</param>
		public void _onSampleEvent (IEvent aIEvent)
		{
			Debug.Log ("\tListening: _onSampleEvent() aIEvent: " + aIEvent + " with customValue: " + (aIEvent as SampleEvent).customValue);
		}
	}
}



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: