前言:

在软件开发过程中,我们都希望能设计出一个稳健的,可维护的系统,为了实现这个目的,人们总结出了很多相关的设计原则,比如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

引用:

  1. Amit Patel.《Hexagonal Grids 》https://www.redblobgames.com/grids/hexagons/
  2. Catlike Coding.《Hex Map》https://catlikecoding.com/unity/tutorials/hex-map/
  3. Robert C.Martin. 《架构整洁之道》

通用游戏地图解决方案设计解析相关推荐

  1. 字节跳动必问面试题——通用型业务解决方案设计

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 前言 受邀参加过字节跳动面试的小伙伴一般都会收到一封面试邀请的邮件 ...

  2. 现代化蔬菜大棚采用什么和计算机自动控制,温室大棚中温室自动化控制系统解决方案设计...

    原标题:温室大棚中温室自动化控制系统解决方案设计 温室自动控制系统是专门为农业温室.农业环境控制.气象观测开发生产的环境自动控制系统.可测量风向.风速.温度.湿度.光照.气压.雨量.太阳辐射量.太阳紫 ...

  3. 2021年施工员-装饰方向-通用基础(施工员)最新解析及施工员-装饰方向-通用基础(施工员)免费试题

    题库来源:安全生产模拟考试一点通公众号小程序 安全生产模拟考试一点通:施工员-装饰方向-通用基础(施工员)最新解析根据新施工员-装饰方向-通用基础(施工员)考试大纲要求,安全生产模拟考试一点通将施工员 ...

  4. 解决:无法解析的外部符号__iob_func

    解决:无法解析的外部符号__iob_func 原文:http://blog.csdn.net/hebbely/article/details/53780562 在使用 VS2015 下使用 libjp ...

  5. socket Php 粘包,python3 tcp的粘包现象和解决办法解析

    这篇文章主要介绍了python3 tcp的粘包现象和解决办法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 服务器端 import socket ...

  6. 2020年市政方向-通用基础(施工员)答案解析及市政方向-通用基础(施工员)考试总结

    题库来源:安全生产模拟考试一点通公众号小程序 2020年市政方向-通用基础(施工员)答案解析及市政方向-通用基础(施工员)考试总结,包含市政方向-通用基础(施工员)答案解析答案和解析及市政方向-通用基 ...

  7. VS2015下解决:无法解析的外部符号 __imp___vsnprintf 及__iob_func

    1.解决:无法解析的外部符号 __imp___vsnprintf 在 vs2015 工程选项,链接器附加依赖项里面添加 legacy_stdio_definitions.lib 即可. 出现这个问题的 ...

  8. 解决ini-parser解析ini文件中文乱码问题

    解决ini-parser解析ini文件中文乱码问题 参考文章: (1)解决ini-parser解析ini文件中文乱码问题 (2)https://www.cnblogs.com/nodegis/p/95 ...

  9. 电力信息采集的通用型通信规约解析系统研究与设计

    电力信息采集的通用型通信规约解析系统研究与设计 蒋湘涛 http://xueshu.baidu.com/s?wd=paperuri%3A%28a61890f7723743df132caf246fd0a ...

最新文章

  1. 太牛了!22岁本科生Github上开源的后台管理系统,太实用(附源码)!
  2. jQuery Mobile手机网站案例
  3. java类定义的顺序_Java类及对象的初始化顺序
  4. 第三节:Web爬虫之BeautifulSoup解析库
  5. 72年属鼠48岁有一灾2020_李半仙推算:1972年虚岁48岁属鼠人,2020年干什么最能发财??...
  6. axios get请求方式
  7. windows 下后台启动 redis
  8. android sdkversion
  9. 浅谈信息安全及解决方案
  10. 某大型银行深化系统技术方案之十一:核心层之业务活动监控
  11. Hudson:一款持续构建工具
  12. Python虚拟环境的搭建
  13. php socket 超时设置
  14. python property使用
  15. 微信聊天记录生成词云图
  16. 锁仓怎么解_期货如何锁仓,解锁以及锁仓的好处
  17. web课程设计网页制作、基于HTML+CSS大学校园班级网页设计
  18. 福建农林大学计算机分数线,福建农林大学录取分数线2021是多少分(附历年录取分数线)...
  19. 博客项目——登录功能实现
  20. 根据中文名字首字母进行分组

热门文章

  1. [3] JMeter -详解jmeter测试计划
  2. InsecureRequestWarning: Unverified HTTPS request is being made to host ‘127.0.0.1‘.
  3. Qt tabwidget 标签页设置tabbar标题,tabwidget设置透明色
  4. win7关闭加域用户下5分钟锁屏
  5. item_recommend - 获取推荐商品列表
  6. 上一根烟.点上心里的想念 伤感日志
  7. Java接入sqlserver的一些坑点记录
  8. 映射SharePoint 2013管理中心到外网的方法
  9. IE下载文件,没有提示保存的解决方法(zz)
  10. 竞品分析——网易蜗牛读书