游戏框架通用模块之一消息机制

Posted 雨尘无痕

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了游戏框架通用模块之一消息机制相关的知识,希望对你有一定的参考价值。

使用方式:

注册消息: 在需要的位置注册一个带string参数的接收消息函数

CoreRoot.eventMgr.AddListener<string>("gmCommand", OnGmCommand);

发送消息:

CoreRoot.eventMgr.TriggerEvent<string>("gmCommand", inputField.text);

 

消息机制核心代码:

//支持的功能包括,事件的优先级排序,是否在切换场景时移除,每个委托可能绑定多个事件
public class EventMgr : MonoBehaviour



    //定义优先级

public enum EventPriority
    
        Highest        = 10,
        High        = 100,
        AboveMedium = 150,
        Medium        = 200,            // 默认优先级
        BelowMedium = 250,
        Low            = 300,
        Lowest        = 400,
    

//支持从0到3个参数的委托,

    public delegate void EventFunction(string ge);
    public delegate void EventFunction<U>(string ge, U arg1);
    public delegate void EventFunction<U, V>(string ge, U arg1, V arg2);
    public delegate void EventFunction<U, V, W>(string ge, U arg1, V arg2, W arg3);

    //定义事件类
    public class EventNode
	
		public EventNode(Delegate function, bool removeOnLoadScene, EventPriority priority)
		
			this.function = function;
			this.removeOnLoadScene = removeOnLoadScene;
			this.priority = priority;
		
		
		public Delegate function;
		public bool removeOnLoadScene;
		public EventPriority priority;
	

    //按优先级排序
    public class EventNodeCompare : IComparer<EventNode>
	
		public int Compare(EventNode x, EventNode y)
		
			if (x == null)
			
				if (y == null)
					return 0;
				else
					return -1;
			
			else
			
				if (y == null)
					return 1;
				else
					return ((int)x.priority) - ((int)y.priority);
			
		
	

    public class MapNode
	
		public bool dirty = false;
		public List<EventNode> nodeList = new List<EventNode>();
	

    void Awake ()
	
		eventMap = new Dictionary<string, MapNode>();
	

    // removeOnLoadScene决定此监听注册是否在加载场景时自动移除,大部分监听都应该选择自动移除,这是防止内存泄漏的保障机制
	public void AddListener(string ge, EventFunction ef, bool removeOnLoadScene = true, EventPriority priority = EventPriority.Medium)
	
		AddListenerInternal(ge, ef, removeOnLoadScene, priority);
	
	
	public void AddListener<U>(string gameEvent, EventFunction<U> ef, bool removeOnLoadScene = true, EventPriority priority = EventPriority.Medium)
	
		AddListenerInternal(gameEvent, ef, removeOnLoadScene, priority);
	
	
	public void AddListener<U, V>(string gameEvent, EventFunction<U, V> ef, bool removeOnLoadScene = true, EventPriority priority = EventPriority.Medium)
	
		AddListenerInternal(gameEvent, ef, removeOnLoadScene, priority);
	
	
	public void AddListener<U, V, W>(string gameEvent, EventFunction<U, V, W> ef, bool removeOnLoadScene = true, EventPriority priority = EventPriority.Medium)
	
		AddListenerInternal(gameEvent, ef, removeOnLoadScene, priority);
	
	
	private void AddListenerInternal(string ge, Delegate ef, bool removeOnLoadScene, EventPriority priority)
	
		// 如果event为空,那么返回
		if (ge == null || ge.Length == 0) 
		
			Debug.LogWarning("EventMgr" + "EventName Error");
			return;
		
		
		// 如果第一次注册此类事件,需要创建对应链表
		MapNode mapNode;
		if( !eventMap.TryGetValue(ge, out mapNode) )
		
			mapNode = new MapNode();
			eventMap[ge] = mapNode;
		
		
		// 如果重复注册则返回
		//foreach( EventNode node in nodeList )
		bool shouldSort = false;
		for (int i=0; i<mapNode.nodeList.Count; ++i)
		
			var node = mapNode.nodeList[i];
			
			if( node.priority != EventPriority.Medium )
				shouldSort = true;
			
			if( node.function.Equals(ef) )
				return;
		
		
		if( priority != EventPriority.Medium )
			shouldSort = true;
		
		mapNode.nodeList.Add( new EventNode(ef, removeOnLoadScene, priority) );
		if( mapNode.nodeList.Count > 1 && shouldSort )
			mapNode.dirty = true;
    
    
	
	public void RemoveListener(string ge, EventFunction ef)
	
		RemoveListenerInternal(ge, ef);
	
	
	public void RemoveListener<U>(string ge, EventFunction<U> ef)
	
		RemoveListenerInternal(ge, ef);
	
	
	public void RemoveListener<U, V>(string ge, EventFunction<U, V> ef)
	
		RemoveListenerInternal(ge, ef);
	
	
	public void RemoveListener<U, V, W>(string ge, EventFunction<U, V, W> ef)
	
		RemoveListenerInternal(ge, ef);
	
	
	public void RemoveListenerInternal(string ge, Delegate ef)
	
		MapNode mapNode;
		if( !eventMap.TryGetValue(ge, out mapNode) )
			return;
		
		int nCount = 0;
		foreach( EventNode node in mapNode.nodeList )
		
			if( node.function.Equals(ef) )
				
				mapNode.nodeList.RemoveAt(nCount);
				return;
			
			
			nCount++;
		
	
	
	EventNode[] PrepareNodeList(string ge)
	
		if (ge == null || ge.Length == 0)
		
			//CoreEntry.logMgr.Log(LogLevel.WARNING, "EventMgr", "trigger null event");
			return null;
		
		
		MapNode mapNode;
		if( !eventMap.TryGetValue(ge, out mapNode) )
			return null;
		
		if( mapNode.dirty )
		
			mapNode.nodeList.Sort(eventNodeCompare);
			mapNode.dirty = false;
		
		
		// 将事件响应队列复制一个副本
		EventNode[] tpList = new EventNode[ mapNode.nodeList.Count ];
		mapNode.nodeList.CopyTo(tpList);
		return tpList;
	
	
	public void TriggerEvent(string ge)
	
		EventNode[] tpList = PrepareNodeList(ge);
		if( tpList == null )
			return;
		
		foreach( EventNode node in tpList )
		
			EventFunction ef = node.function as EventFunction;
			if( ef != null )
				ef(ge);
			else
				Debug.LogError(string.Format("处理事件 \\"0\\" 时回调函数参数不匹配", ge) );
		
	
	
	public void TriggerEvent<U>(string ge, U arg1)
	
		EventNode[] tpList = PrepareNodeList(ge);
		if( tpList == null )
			return;
		
		foreach( EventNode node in tpList )
		
			EventFunction<U> ef = node.function as EventFunction<U>;
			if( ef != null )
				ef(ge, arg1);
			else
				Debug.LogError(string.Format("处理事件 \\"0\\" 时回调函数参数不匹配", ge) );
		
	
	
	public void TriggerEvent<U, V>(string ge, U arg1, V arg2)
	
		EventNode[] tpList = PrepareNodeList(ge);
		if( tpList == null )
			return;
		
		foreach( EventNode node in tpList )
		
			EventFunction<U, V> ef = node.function as EventFunction<U, V>;
			if( ef != null )
				ef(ge, arg1, arg2);
			else
				Debug.LogError(string.Format("处理事件 \\"0\\" 时回调函数参数不匹配", ge) );
		
	
	
	public void TriggerEvent<U, V, W>(string ge, U arg1, V arg2, W arg3)
	
		EventNode[] tpList = PrepareNodeList(ge);
		if( tpList == null )
			return;
		
		foreach( EventNode node in tpList )
		
			EventFunction<U, V, W> ef = node.function as EventFunction<U, V, W>;
			if( ef != null )
				ef(ge, arg1, arg2, arg3);
			else
				Debug.LogError(string.Format("处理事件 \\"0\\" 时回调函数参数不匹配", ge) );
		
	
	
	// 切换场景时移除removeOnLoadScene标志为true的监听对象
	public void OnLoadSceneRecycle()
	
		foreach( MapNode mapNode in eventMap.Values )
		
			for( int i=0; i<mapNode.nodeList.Count; )
			
				if( mapNode.nodeList[i].removeOnLoadScene )
					mapNode.nodeList.RemoveAt(i);
				else
					++i;
			
		
	

 

以上是关于游戏框架通用模块之一消息机制的主要内容,如果未能解决你的问题,请参考以下文章

WebRTC 源码分析之一:几个核心设计概念

Android 开发: Android 消息处理机制之一: Handler 与 Message

CabloyJS 4.7.0:支持通用静态渲染机制

使用 Python 和 Pygame 模块构建一个游戏框架

linux epoll机制对TCP 客户端和服务端的监听C代码通用框架实现

U3D游戏开发框架——消息系统