來說說組件(Components)模式

1.什麼是組件模式?通俗點講,我覺得他像一個機械工程一樣,像飛機,潛艇,他有許多的零件系統組成,各個零件部門相互獨立,獨立來加工,等把需要的組件零件都加工生產完成之後,由組裝師組成一個完整的個體,而要啓動這個整體飛機要起飛,潛艇要發射炮彈,各個系統組件都協調有序的運行起來。而這些組件又想獨立於系統,隨時可以進行更換,進行升級。
3,遊戲中最常見的就是任務角色的設計,組件模式用的比較多,還有就是slg類的遊戲,像建築的升級,城堡的建設等等。我們今天來實現一個人物角色的組件設計模式。一個Avatar通常可以飛,可以跑,可能會受到傷害,可以攻擊別人,這樣我們都可以把這些行爲作爲一個組件,然後我們一個角色就可以隨意的來進行組合,來達到我們要的效果。

2.在遊戲中是怎麼使用的?現在的遊戲中大量的用到了組件模式,他比繼承更具有解偶性。他更加的方便維護,來進行開發,一個好的遊戲系統設計出來,當引擎無論的怎麼更替,業務邏輯怎麼樣的變更,仍然能夠井井有序思路清晰的來開發,並且bug率很少,好多比較次的遊戲系統中一個文件的代碼達到好幾千行,像這樣看着都費勁,更別說可讀性了,從而整個開發的效率成幾何一樣的下降,並且全是bug,這樣你很難去管理,同時坑隊友。

我們創建一個實體EntityBase類,來作爲一個主體。

using System;
using System.Collections.Generic;
using UnityEngine;

public class EntityBase
{

	public IDictionary<string ,ComponentBase> componentMaps = new Dictionary<string,ComponentBase>();
 	
	/// <summary>
	/// 加入組件方法
	/// </summary>
	/// <param name="key">Key.</param>
	/// <param name="comptBase">Compt base.</param>
	public void AddComponent(string key,ComponentBase  comptBase)
	{
		if (comptBase == null) 
		{
			Debug.Log ("add component failed: comptbase == null");
		}

		if(!componentMaps.ContainsKey(key))
		{
			componentMaps.Add (key,comptBase);
			this.AttachedComponent (comptBase);
			comptBase.AddFromEntity (this);
		}
	}

	/// <summary>
	///通過Key值來刪除組件
	/// </summary>
	/// <param name="key">Key.</param>
	public  void RemoveComponent(string key)
	{
		if(componentMaps.ContainsKey(key))
		{
			this.RemovedComponent (	componentMaps[key]);
			componentMaps [key].RemovFromEntity (this);
			componentMaps.Remove (key);
		}

	}
		
	///<summary>
	/// 發送事件
	/// </summary>
	/// 
	public bool DispatchEvent(Event events)
	{	
		bool flag_1 = false;
		//發送一個時間   看cpt 對象那些註冊該時間,註冊了則進行調用
		foreach(ComponentBase  pts in componentMaps.Values)
		{	
			//怎麼知道有沒有註冊改事件  註冊成功就會調用各個組件的方法 返回TRUE 則爲調用成功,執行成功
			bool flag = pts.OnEvent (events);
			flag_1 = (flag_1 || flag);
		}

		if (flag_1 == false) {
			Debug.Log ("Dispatch falies!");
		}

		return flag_1;
	}

	/// <summary>
	/// 添加成功了組件回調
	/// </summary>
	/// <param name="cptBase">Cpt base.</param>
	public virtual void AttachedComponent(ComponentBase cptBase)
	{
		
	}

	/// <summary>
	/// 移除成功了改組件
	/// </summary>
	/// <param name="cptBase">Cpt base.</param>
	public virtual void RemovedComponent(ComponentBase cptBase)
	{

	}
}


再來創建一個component的基礎類

using System;
using System.Collections.Generic;

public class ComponentBase
{
	protected EntityBase entityBase;
	public  delegate  void  EventHandleFunction(Event events); 

	private Dictionary<int,EventHandleFunction> EventHandlerMap = new Dictionary<int,EventHandleFunction>();

	///<summary>
	/// 向entity上面添加了此組件
	/// </summary>
	public virtual void AddFromEntity(EntityBase entityBase)
	{
		entityBase = entityBase;
	}

	/// <summary>
	/// 從entity移除了該組件
	/// </summary>
	public virtual void RemovFromEntity(EntityBase ety)
	{
		entityBase = null;
	}

	/// <summary>
	///看有沒有註冊該事件
	/// </summary>
	/// <returns><c>true</c>, if event was oned, <c>false</c> otherwise.</returns>
	/// <param name="events">Events.</param>
	public bool OnEvent(Event events)
	{
		EventHandleFunction handerFunction;
		//有沒有註冊改類事件
		if(EventHandlerMap.TryGetValue(events.event_id, out handerFunction) == false)
		{
			return false;
		}

		if(handerFunction == null)
		{
			return false;
		}

		handerFunction (events);

		return true;
	}

	///<summary>
	/// 註冊事件
	/// </summary>
	public void RegistEvent(int eventID,EventHandleFunction  handlerFunction)
	{
		if(EventHandlerMap.ContainsKey(eventID))
		{
			EventHandlerMap.Remove (eventID);
		}
		EventHandlerMap.Add(eventID,handlerFunction);
	}


	/// <summary>
	/// 移除註冊的事件
	/// </summary>
	/// <param name="eventID">Event I.</param>
	/// <param name="handlerFunction">Handler function.</param>
	public void UnRegistEvent(int eventID)
	{
		if(EventHandlerMap.ContainsKey(eventID))
		{
			EventHandlerMap.Remove (eventID);
		}
	}

}
組件和實體怎麼通信的,我們來創建一個通信的事件類

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class Event
{
	public int event_id;
	ArrayList eventArags = new ArrayList();
 
	public void pushUserData<T>( T Data)
	{
		eventArags.Add (Data);
	}

	public T getUserData<T>(int event_id)
	{
		if(event_id > eventArags.Count)
		{
			return default(T);
		}
		return (T)eventArags[event_id];
	}

}

在來創建一個事件類型的枚舉

using System;
public enum EventDefine
{
	Event_01 = 0,
	Event_02,
	Event_03,
	Event_04,
}


好了我們基本的封裝底層基本上已經實現了,我們來做個測試,我們分別來創建一個FlyComponent 和 RuningComponent 的組件


using System;
using UnityEngine;

public class FlyComponent :ComponentBase
{

	public override void AddFromEntity(EntityBase entityBase)
	{
		base.AddFromEntity (entityBase);

		RegistEvent ((int)(EventDefine.Event_01),DealEvent01);
		RegistEvent ((int)(EventDefine.Event_03),DealEvent03);
	}
		
	public override void RemovFromEntity(EntityBase ety)
	{
		base.RemovFromEntity (ety);
	}

	private void DealEvent01(Event evt)
	{
		string evtData = evt.getUserData<string>(0);
		Debug.Log("FlyComponent Handle Event: ID = " + evt.event_id.ToString());
		Debug.Log("FlyComponent Handle Event: Data = " + evtData);
		Debug.Log("我開始飛起來了================");
	}

	private void DealEvent03(Event evt)
	{
		float evtData = evt.getUserData<float>(0);
		Debug.Log("FlyComponent Handle Event: ID = " + evt.event_id.ToString());
		Debug.Log("FlyComponent Handle Event: Data = " + evtData);
		Debug.Log("飛啊  飛啊 ================");
	}

}

using System;
using UnityEngine;

public class RuningComponent : ComponentBase
{

	public override void AddFromEntity(EntityBase entityBase)
	{
		base.AddFromEntity (entityBase);

		RegistEvent ((int)(EventDefine.Event_02),Event_02);
		RegistEvent ((int)(EventDefine.Event_04),Event_04);
	}


	public override void RemovFromEntity(EntityBase ety)
	{
		base.RemovFromEntity (ety);
	}

	private void Event_02(Event evt)
	{
		string evtData = evt.getUserData<string>(0);
		Debug.Log("RuningComponent Handle Event: ID = " + evt.event_id.ToString());
		Debug.Log("RuningComponent Handle Event: Data = " + evtData);

		Debug.Log("跑起來了  跑起來了================");
	}

	private void Event_04(Event evt)
	{
		float evtData = evt.getUserData<float>(0);
		Debug.Log("RuningComponent Handle Event: ID = " + evt.event_id.ToString());
		Debug.Log("RuningComponent Handle Event: Data = " + evtData);
		Debug.Log("跑啊跑啊  跑================");
	}

}

再來創建一個Avatar實體類

using System;
public class AvatarEntity  : EntityBase
{
	public AvatarEntity()
	{
		InitComponents ();
	}

	public void InitComponents()
	{
		FlyComponent flyComp = new FlyComponent();
		AddComponent("FlyComponent", flyComp);

	
		RuningComponent runComp = new RuningComponent();
		AddComponent("RuningComponent", runComp);
	}

	/// <summary>
	/// 調用跑的接口
	/// </summary>
	public virtual void Fly()
	{
		// 發送消息Event_01
		Event evt1 = new Event();
		evt1.event_id = (int)EventDefine.Event_01;
		evt1.pushUserData<string>("SomeData For Event01");
		DispatchEvent(evt1);
	}

	/// <summary>
	/// 開始跑了
	/// </summary>
	public virtual void Runing()
	{
		// 發送消息Event_02
		Event evt2 = new Event();
		evt2.event_id = (int)EventDefine.Event_02;
		evt2.pushUserData<string>("SomeData For Event02");
		DispatchEvent(evt2);


	}
}



大功告成,我們來直接測試了

//測試組件模式
var  avatEntity =  new AvatarEntity ();
avatEntity.Fly ();//飛起來了
avatEntity.Runing ();//跑了


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章