|
对于配置表,我准备使用一个GameConfig组件来存放所有的配置:
- <blockquote>public class GameConfig : Component
复制代码
这样,在加载GameConfig组件的时候,就会调用对应的Awake事件,所以可以写一个Awake事件来加载所有的配置组件,而这些配置组件将都放在GameConfig的configEntity组件上。
- [EventSystem(typeof(GameConfig))]
- public class AwakeSystem : IAwakeSystem, IAwake
- {
- public void Awake(Component component)
- {
- if (component is GameConfig game)
- {
- game.configEntity = (Entity)Game.ObjectPool.Get<Entity>();
- }
- }
- }
复制代码
在加载GameConfig这个组件时,就会执行这一事件。
接下来就是具体配置表的载入了,这时候需要定义一种新的事件类型,这种事件类型不似awake事件那样具有通用性,通过类名来存储,而是通过事件名来存储,所以需要新建一个事件类型:
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
- public class EventSystemAttribute : Attribute
- {
- ……
- public string eventType;
- ……
- public EventSystemAttribute(string type)
- {
- eventType = type;
- }
- }
复制代码
在原来的EventSystemAttribute类中,加入一个新的参数string类型的eventType。
- public interface IEventSystem
- {
- }
- public interface IEvent
- {
- void Handle(Component component);
- }
复制代码
设计一个对应该函数的接口。
- public class EventSystem
- {
- ……
- private readonly ListDictionary<string, IEventSystem> eventSystems = new ListDictionary<string, IEventSystem>();
- ……
- public void InitSystems()
- {
- foreach (Type type in Assembly.GetTypes())
- {
- object[] objects = Attribute.GetCustomAttributes(type);
- if (objects.Length == 0)
- {
- continue;
- }
- foreach (object obj in objects)
- {
- if (obj is EventSystemAttribute e)
- {
- object sys = Activator.CreateInstance(type);
- if (sys is IAwakeSystem awake)
- {
- awakeSystems.Add(e.ClassType, awake);
- }
- if (sys is IEventSystem evt)
- {
- eventSystems.Add(e.eventType, evt);
- }
- }
- }
- }
- }
- ……
- }
复制代码
而后将接口加载到EventSystem类中。
- public class EventSystem
- {
- ……
- public void ExecuteEvent(Component component,string eventType)
- {
- List<IEventSystem> systems = eventSystems.Get(eventType);
- if (systems == null)
- {
- return;
- }
- foreach (IEventSystem ievent in systems)
- {
- try
- {
- if (ievent is IEvent evt)
- {
- evt?.Handle(component);
- }
- }
- catch(Exception e)
- {
- Debug.Log(e.ToString());
- }
- }
- }
- }
复制代码
然后再通过这个函数来调用它。
接下来就是在GameConfig的Awake函数里调用这个函数:
- [EventSystem(typeof(GameConfig))]
- public class GameConfigAwake : IAwakeSystem, IAwake
- {
- public void Awake(Component component)
- {
- if (component is GameConfig game)
- {
- game.configEntity = (Entity)Game.ObjectPool.Get<Entity>();
- Game.EventSystem.ExecuteEvent(game, EventType.InitConfigEvent);
- }
- }
- }
复制代码
然而,用string作为类型是很容易出错的,因为很容易打错字。所以可以用一个部分类来作为可扩展的类型表:
- static partial class EventType
- {
- public const string InitConfigEvent = "InitGameConfigEvent";
- }
复制代码
这样就可以在多个地方同时编辑EventType类了,比如:
文件一:
- static partial class EventType
- {
- public const string InitConfigEvent = "InitGameConfigEvent";
- }
复制代码
文件二:
- static partial class EventType
- {
- public const string AnotherEvent = "AnotherEvent";
- }
复制代码
这样,以后添加新的事件的时候,就不用再打开某个固定的EventType类文件去改,只需在一个文件里就可以做到在EventType类中添加新的变量名。记得让字符串的内容和类型名写成一样,这样可以避免事件名有重复。
好了,准备了这么多,可以开始做正事了,加载配置表,首先是加载科技花费的表:
这张表需要加载的其实只是下面这几个:
保存的结构很简单:
- public class TechnologyCost : Component
- {
- public Dictionary<int, int> cost;
- public int GetCost(int level)
- {
- return cost[level];
- }
- }
复制代码
接下来就是写一个事件,加载这个组件到GameConfig的configEntity实体上
- [EventSystem(EventType.InitConfigEvent)]
- public class LoadTechnologyCost : IEventSystem, IEvent
- {
- public void Handle(Component component)
- {
- if (component is GameConfig game)
- {
- game.configEntity.AddComponent<TechnologyCost>();
- }
- }
- }
复制代码
EventSystem(EventType.InitConfigEvent)意味着这个事件将加载到EventSystem.eventSystems中。并在GameConfigAwake这一事件中调用。
接下来是具体的加载,我将加载的方法放在了TechnologyCost组件的Awake方法中:
- [EventSystem(typeof(TechnologyCost))]
- public class AwakeTechnologyCost : IAwakeSystem, IAwake
- {
- public void Awake(Component component)
- {
- if (component is TechnologyCost techCost)
- {
- techCost.cost = new Dictionary<int, int>();
- List<string[]> costFile = CSVUtil.Process("CSV/technologyCost");
- int key;
- int value;
- for (int i = 0; i < costFile.Count; i++)
- {
- if (i == 0)
- continue;
- if (costFile[i] != null)
- {
- try
- {
- key = Convert.ToInt32(costFile[i][0]);
- value = Convert.ToInt32(costFile[i][1]);
- if (!techCost.cost.ContainsKey(key))
- {
- techCost.cost.Add(key, value);
- }
- }
- catch (Exception e)
- {
- Debug.Log(e.ToString());
- }
- }
- }
- foreach (KeyValuePair<int, int> valuePair in techCost.cost)
- {
- Debug.LogFormat("level:{0} cost:{1}", valuePair.Key, valuePair.Value);
- }
- }
- }
- }
复制代码
最后几行,会把读取后的内容打印出来用于测试,将来会去掉。
加载的代码原理和上面的一样,我就直接放出来了。
- <blockquote>using System;
复制代码
这样,以后每要加载一个新的配置表,都只需要在一个文件里改就行了,不用同时修改多个文件,这也是前面做了一大堆准备工作的目的所在。
相关阅读:
从零开始做一个SLG游戏(一):六边形网格
从零开始做一个SLG游戏(二):用mesh实现简单的地形
从零开始做一个SLG游戏(三):用unity绘制图形
从零开始做一个SLG游戏(四):UI系统之主界面搭建
从零开始做一个SLG游戏(五):UI系统之弹窗功能
从零开始做一个SLG游戏(六):UI系统扩展
从零开始做一个SLG游戏(七):游戏系统以及配置表
作者:观复
专栏地址:https://zhuanlan.zhihu.com/p/70715555
|
|