從零開始做一個SLG遊戲(八):配置表載入元件

遊資網發表於2019-11-01
從零開始做一個SLG遊戲(八):配置表載入元件

對於配置表,我準備使用一個GameConfig元件來存放所有的配置:

  1. <blockquote>public class GameConfig : Component
複製程式碼

這樣,在載入GameConfig元件的時候,就會呼叫對應的Awake事件,所以可以寫一個Awake事件來載入所有的配置元件,而這些配置元件將都放在GameConfig的configEntity元件上。

  1. [EventSystem(typeof(GameConfig))]
  2. public class AwakeSystem : IAwakeSystem, IAwake
  3. {
  4.         public void Awake(Component component)
  5.         {
  6.                 if (component is GameConfig game)
  7.                 {
  8.                         game.configEntity = (Entity)Game.ObjectPool.Get<Entity>();
  9.                 }
  10.         }
  11. }
複製程式碼

在載入GameConfig這個元件時,就會執行這一事件。

接下來就是具體配置表的載入了,這時候需要定義一種新的事件型別,這種事件型別不似awake事件那樣具有通用性,通過類名來儲存,而是通過事件名來儲存,所以需要新建一個事件型別:

  1. [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
  2. public class EventSystemAttribute : Attribute
  3. {
  4.         ……
  5.         public string eventType;
  6.         ……
  7.         public EventSystemAttribute(string type)
  8.         {
  9.                 eventType = type;
  10.         }
  11. }
複製程式碼

在原來的EventSystemAttribute類中,加入一個新的引數string型別的eventType。

  1. public interface IEventSystem
  2. {

  3. }

  4. public interface IEvent
  5. {
  6.         void Handle(Component component);
  7. }
複製程式碼

設計一個對應該函式的介面。

  1. public class EventSystem
  2. {
  3.         ……
  4.         private readonly ListDictionary<string, IEventSystem> eventSystems = new ListDictionary<string, IEventSystem>();
  5.         ……
  6.         public void InitSystems()
  7.         {
  8.                 foreach (Type type in Assembly.GetTypes())
  9.                 {
  10.                         object[] objects = Attribute.GetCustomAttributes(type);
  11.                         if (objects.Length == 0)
  12.                         {
  13.                                 continue;
  14.                         }
  15.                         foreach (object obj in objects)
  16.                         {
  17.                                 if (obj is EventSystemAttribute e)
  18.                                 {
  19.                                         object sys = Activator.CreateInstance(type);
  20.                                         if (sys is IAwakeSystem awake)
  21.                                         {
  22.                                                 awakeSystems.Add(e.ClassType, awake);
  23.                                         }
  24.                                         if (sys is IEventSystem evt)
  25.                                         {
  26.                                                 eventSystems.Add(e.eventType, evt);
  27.                                         }
  28.                                 }
  29.                         }
  30.                 }
  31.         }
  32.         ……
  33. }
複製程式碼

而後將介面載入到EventSystem類中。

  1. public class EventSystem
  2. {
  3.         ……
  4.         public void ExecuteEvent(Component component,string eventType)
  5.         {
  6.                 List<IEventSystem> systems = eventSystems.Get(eventType);
  7.                 if (systems == null)
  8.                 {
  9.                         return;
  10.                 }
  11.                 foreach (IEventSystem ievent in systems)
  12.                 {
  13.                         try
  14.                         {
  15.                                 if (ievent is IEvent evt)
  16.                                 {
  17.                                         evt?.Handle(component);
  18.                                 }
  19.                         }
  20.                         catch(Exception e)
  21.                         {
  22.                                 Debug.Log(e.ToString());
  23.                         }
  24.                 }
  25.         }
  26. }
複製程式碼

然後再通過這個函式來呼叫它。

接下來就是在GameConfig的Awake函式裡呼叫這個函式:

  1. [EventSystem(typeof(GameConfig))]
  2. public class GameConfigAwake : IAwakeSystem, IAwake
  3. {
  4.         public void Awake(Component component)
  5.         {
  6.                 if (component is GameConfig game)
  7.                 {
  8.                         game.configEntity = (Entity)Game.ObjectPool.Get<Entity>();
  9.                         Game.EventSystem.ExecuteEvent(game, EventType.InitConfigEvent);
  10.                 }
  11.         }
  12. }
複製程式碼

然而,用string作為型別是很容易出錯的,因為很容易打錯字。所以可以用一個部分類來作為可擴充套件的型別表:

  1. static partial class EventType
  2. {
  3.         public const string InitConfigEvent = "InitGameConfigEvent";
  4. }
複製程式碼

這樣就可以在多個地方同時編輯EventType類了,比如:

檔案一:

  1. static partial class EventType
  2. {
  3.         public const string InitConfigEvent = "InitGameConfigEvent";
  4. }
複製程式碼

檔案二:

  1. static partial class EventType
  2. {
  3.         public const string AnotherEvent = "AnotherEvent";
  4. }
複製程式碼

這樣,以後新增新的事件的時候,就不用再開啟某個固定的EventType類檔案去改,只需在一個檔案裡就可以做到在EventType類中新增新的變數名。記得讓字串的內容和型別名寫成一樣,這樣可以避免事件名有重複。

好了,準備了這麼多,可以開始做正事了,載入配置表,首先是載入科技花費的表:

從零開始做一個SLG遊戲(八):配置表載入元件

這張表需要載入的其實只是下面這幾個:

從零開始做一個SLG遊戲(八):配置表載入元件

儲存的結構很簡單:

  1. public class TechnologyCost : Component
  2. {
  3.         public Dictionary<int, int> cost;
  4.         public int GetCost(int level)
  5.         {
  6.                 return cost[level];
  7.         }
  8. }
複製程式碼

接下來就是寫一個事件,載入這個元件到GameConfig的configEntity實體上

  1. [EventSystem(EventType.InitConfigEvent)]
  2. public class LoadTechnologyCost : IEventSystem, IEvent
  3. {
  4.         public void Handle(Component component)
  5.         {
  6.                 if (component is GameConfig game)
  7.                 {
  8.                         game.configEntity.AddComponent<TechnologyCost>();
  9.                 }
  10.         }
  11. }
複製程式碼

EventSystem(EventType.InitConfigEvent)意味著這個事件將載入到EventSystem.eventSystems中。並在GameConfigAwake這一事件中呼叫。

接下來是具體的載入,我將載入的方法放在了TechnologyCost元件的Awake方法中:

  1. [EventSystem(typeof(TechnologyCost))]
  2. public class AwakeTechnologyCost : IAwakeSystem, IAwake
  3. {
  4.         public void Awake(Component component)
  5.         {
  6.                 if (component is TechnologyCost techCost)
  7.                 {
  8.                         techCost.cost = new Dictionary<int, int>();
  9.                         List<string[]> costFile = CSVUtil.Process("CSV/technologyCost");
  10.                         int key;
  11.                         int value;
  12.                         for (int i = 0; i < costFile.Count; i++)
  13.                         {
  14.                                 if (i == 0)
  15.                                         continue;
  16.                                 if (costFile[i] != null)
  17.                                 {
  18.                                         try
  19.                                         {
  20.                                                 key = Convert.ToInt32(costFile[i][0]);
  21.                                                 value = Convert.ToInt32(costFile[i][1]);
  22.                                                 if (!techCost.cost.ContainsKey(key))
  23.                                                 {
  24.                                                         techCost.cost.Add(key, value);
  25.                                                 }
  26.                                         }
  27.                                         catch (Exception e)
  28.                                         {
  29.                                                 Debug.Log(e.ToString());
  30.                                         }
  31.                                 }
  32.                         }
  33.                         foreach (KeyValuePair<int, int> valuePair in techCost.cost)
  34.                         {
  35.                                 Debug.LogFormat("level:{0} cost:{1}", valuePair.Key, valuePair.Value);
  36.                         }
  37.                 }
  38.         }
  39. }
複製程式碼

最後幾行,會把讀取後的內容列印出來用於測試,將來會去掉。

從零開始做一個SLG遊戲(八):配置表載入元件

載入的程式碼原理和上面的一樣,我就直接放出來了。

  1. <blockquote>using System;
複製程式碼

這樣,以後每要載入一個新的配置表,都只需要在一個檔案裡改就行了,不用同時修改多個檔案,這也是前面做了一大堆準備工作的目的所在。

相關閱讀:
從零開始做一個SLG遊戲(一):六邊形網格
從零開始做一個SLG遊戲(二):用mesh實現簡單的地形
從零開始做一個SLG遊戲(三):用unity繪製圖形
從零開始做一個SLG遊戲(四):UI系統之主介面搭建
從零開始做一個SLG遊戲(五):UI系統之彈窗功能

從零開始做一個SLG遊戲(六):UI系統擴充套件
從零開始做一個SLG遊戲(七):遊戲系統以及配置表


作者:觀復
專欄地址:https://zhuanlan.zhihu.com/p/70715555

相關文章