高端企业网站建设蓦然郑州网站建设,wordpress进不到后台,百度小程序给网站做链接,做牛仔裤的小视频网站前言#xff1a;
在软件开发过程中#xff0c;我们都希望能设计出一个稳健的#xff0c;可维护的系统#xff0c;为了实现这个目的#xff0c;人们总结出了很多相关的设计原则#xff0c;比如SOLID原则#xff0c; KISS原则等等。SOLID每个字母代表了一种设计原则…前言
在软件开发过程中我们都希望能设计出一个稳健的可维护的系统为了实现这个目的人们总结出了很多相关的设计原则比如SOLID原则 KISS原则等等。SOLID每个字母代表了一种设计原则具体大家可以去看《架构整洁之道》这本书或者在网上找相关的博客学习。在本系统中将应用这些原则力求得到一个可用好用可理解可改动的通用地图模块。SOLID原则中的D指的是Dependence Inversion Principle中文可以叫依赖倒置原则或者依赖反转原则。其强调的是在处理依赖关系时应当尽可能依赖抽象类型而不是具体实现。 在绝大多数情况下抽象的东西是稳定的在设计这个抽象类或者接口时我们往往会带着前瞻性的思维去考虑这个接口设计得是否合理是否方便使用者去实现去拓展如果一个抽象的对象发生变化了那对应的所有实现一定会发生改变而如果具体实现发生变更不会影响到抽象接口。因此我们有理由判定接口是不太容易变更的如果一个接口被反复修改那一定是设计这个接口的时候有地方不合理接口承担的内容过多或者是接口方法不够通用带进来了一些业务相关的东西。依赖反转原则也是本文主要讨论的原则。
正文
结构组成
本系统主要由三部分内容组成一个是基础的数据结构模块一个是寻路模块一个是地图模块。三个模块功能内聚但也存在耦合为了防止一个模块修改导致其他模块发生变更所以在耦合时尽量使其仅依赖其他模块中的接口因此模块具体实现修改并不会导致其他模块受到影响。下面将简单介绍这三个模块的内容与设计思路。
数据结构模块
基础的数据结构模块提供了一个最小堆和最大堆这是具体的实现其目的是为寻路模块提供服务的寻路模块直接依赖了数据结构模块如果从设计的角度出发这其实是不应该的因为前面说了我们要依赖抽象类或接口而不是具体实现不过我们也可以发现最小堆和最大堆相对来说是一个较稳定的东西其设计完成一旦通过验证就不太会有理由再去修改它们因此可以认为这个虽然是具体实现但是是一个不容易发生变更的具体实现所以直接依赖这个具体实现也是没问题的。如果非常希望解除耦合将这个直接依赖给取消掉我们也可以考虑引入一个IHeap的接口让寻路模块依赖这个接口同时原来的最小堆最大堆实现该接口因此寻路依赖堆实现类变成了寻路和堆实现类均依赖IHeap接口。
原依赖关系 新依赖关系 寻路模块
寻路模块中定义了一个寻路的接口IPathSearch并实现了三种A星算法分别是原始的A星算法和两种经过一定优化后的A星算法实现这个接口的好处在于如果后期我们需要针对特定的场景比如横冲技能使用额外的寻路规则仅需额外再实现一种新的寻路算法并在原本实例化寻路算法的地方改成实例化新的寻路算法即可而使用的地方由于依赖的是IPathSearch接口因此完全不需要做任何修改。
地图模块
地图模块主要分成地图抽象层、地图具体实现和地图生成三个部分具体可查看文章后面的类图或项目代码。
地图抽象层定义了整个地图模块的基本要素和必要方法比如IMapGrid接口定义了地图的基本数据对外的方法等等。该接口依赖INode接口INode接口定义了一个最基础的地图节点是啥样的而IPathNode则在INode的基础上增加了寻路相关的属性。另外定义了一个IMapShow的接口负责处理地图节点的实际显示比如绑定地图数据层和实际节点对象等功能。INodeEntity定义了节点的基本操作比如设置高亮等等。在这个层中定义的接口均不依赖某个具体实现但定义了地图的几乎所有行为在实现功能的前提下保证了该层的稳定性。
地图具体实现则实现了两种常见的游戏地图网格地图和六边形地图。这两种地图实现了IMapGrid的方法并在实例化的地方注入了创建节点的方法使得地图类型和节点可以摆脱依赖便于后面实现同种类的地图不同的节点。
地图生成部分定义了一个生成配置类和生成类配置类负责配置要生成的地图种类地图所处的平面以及各种类地图的一些独有参数。生成类依赖配置来创建具体的地图并为其绑定对应的显示。
系统完整类图 看不清可以去这里查看。
额外的实现细节
系统的整体结构与设计如上文所示为了实现地图的通用和寻路通用还有一些比较巧妙的设计这里进行补充阐述。
在寻路的时候经常会需要从一个节点访问到该节点的一圈邻居但是不同的地图获取某个节点邻居的方式不同为了通用我们需要定义一个方法能直接获取到某节点的所有邻居。本系统定义了一个IDir接口用来获取一个节点四周邻居相对于该节点的索引偏移这样在寻路时可以通过该节点和索引偏移计算出周围所有邻居的节点。在网格地图中分为了两种一种是四方向的一种是八方向的对应的索引偏移列表不同。而对于六边形地图则是另一种索引偏移所以在本系统中分别实现了三个具体实现并通过配置来决定使用哪组偏移列表。为了高效在六边形地图中实现范围高亮六边形使用了Cube coordinates这个名词来自于Amit Patel的《Hexagonal Grids 》中其使用了三个轴来表示每个节点使得在访问邻居时可以在三个轴上做索引偏移大大减少了查找邻居的消耗。这里我最开始是使用了偏移坐标但是在实际去高亮大范围节点时发现并没有那么轻松尤其是高亮可能发生在地图边缘后面忍痛对此做了重构改用立方体坐标了。在处理扇形高亮时实际上就是从圆形高亮中抠出一部分因此其内部是判断一个朝向并根据扇形宽度算出扇形左右最大偏移角最后调用圆形高亮的方法并添加一个角度的Filter对节点做筛选。地图配置类中增加了编辑器类来对配置类Inspector界面做个性化显示根据选取的地图类型来展示该类型所需要的独有参数并隐藏无关的参数。
总结
以上便是整个地图系统的全部内容和设计思路了在类图中箭头代表了依赖关系走向A指向B表示A依赖B。从图中不难看出箭头指向的对象基本都是接口抽象类或者是一些不太会发生变化的东西。如数据结构小节中的图示即便依赖的对象是具体实现我们也可以引入更抽象的接口对象实现依赖反转使得整个依赖关系走向更合理系统更稳定可靠。当然这个系统并不完善也可能不如料想的那般好用但我希望通过开源出来给更多的人看见给更多的人使用并提供反馈来完善这个东西使得其可以代代相传(doge。
项目地址
https://github.com/tang-xiaolong/MapGridInUnity
引用
Amit Patel.《Hexagonal Grids 》https://www.redblobgames.com/grids/hexagons/Catlike Coding.《Hex Map》https://catlikecoding.com/unity/tutorials/hex-map/Robert C.Martin. 《架构整洁之道》