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 ();//跑了