游戏开发论坛

 找回密码
 立即注册
搜索
查看: 3895|回复: 0

从零开始做一个SLG游戏(八):配置表加载组件

[复制链接]

1万

主题

1万

帖子

3万

积分

论坛元老

Rank: 8Rank: 8

积分
36572
发表于 2019-11-1 13:57:42 | 显示全部楼层 |阅读模式
105432eth6xltlfcxxlcll.png

对于配置表,我准备使用一个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类中添加新的变量名。记得让字符串的内容和类型名写成一样,这样可以避免事件名有重复。

好了,准备了这么多,可以开始做正事了,加载配置表,首先是加载科技花费的表:

1.jpg

这张表需要加载的其实只是下面这几个:

2.png

保存的结构很简单:

  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. }
复制代码

最后几行,会把读取后的内容打印出来用于测试,将来会去掉。

4.jpg

加载的代码原理和上面的一样,我就直接放出来了。

  1. <blockquote>using System;
复制代码

这样,以后每要加载一个新的配置表,都只需要在一个文件里改就行了,不用同时修改多个文件,这也是前面做了一大堆准备工作的目的所在。

相关阅读:
从零开始做一个SLG游戏(一):六边形网格
从零开始做一个SLG游戏(二):用mesh实现简单的地形
从零开始做一个SLG游戏(三):用unity绘制图形
从零开始做一个SLG游戏(四):UI系统之主界面搭建
从零开始做一个SLG游戏(五):UI系统之弹窗功能

从零开始做一个SLG游戏(六):UI系统扩展
从零开始做一个SLG游戏(七):游戏系统以及配置表


作者:观复
专栏地址:https://zhuanlan.zhihu.com/p/70715555

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2024-11-24 10:02

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表