目标
向战场中添加战斗单位,完成简单的战斗循环,看起来的样子是:
1、战场中的对战双方轮流行动,可进行移动、攻击;
2、攻击将对敌人造成伤害;
3、没有生命值的战斗单位会被从战场中移除;
4、当一方被全部消灭时,战斗结束。
实现后的效果如下图:
|准备工作
在开始之前,我们先做一些准备工作。
显示格子坐标
为格子添加Text Mesh Pro组件以显示格子坐标,方便调试。
增加地图功能:放置出生点
我不想看到战斗单位在刚进入战场的时候是随机摆放位置的,因此我需要为它们提供一些出生点。这样当战斗单位初入战场时,会向战斗地图请求一个本方可用的出生点,如果请求成功则加入战场,并设定在那个位置上;如果请求失败则不会进入战场,避免出现乱占位置的情况。
增加地图功能:寻找最近可用格子
指定一个起点和一个终点,返回一个环绕终点的距离起点最近、且可用的格子。这主要是为了战斗单位在确定攻击目标后,需要选择一个它身边的格子作为移动的目标格子(目前假定所有战斗单位的攻击半径都为1)。
这里选择了一种比较偷懒的方法,就是将导航位置直接设定在目标单位的身上,如果导航成功,则将到达终点的前一个格子作为目标格子,这样不仅确定了目标格子,同时还将导航路径一并算出。
准备工作到此为止,下面开始加入战斗单位。
|添加战斗单位
因为是六边形瓦片地图组成的战棋游戏,因此我将战斗单位也表示成六边形,目前来看两者的Prefab并没有什么差别,通过设置Order值来确保战斗单位显示在地图格子的上方。
为了更好的区分战场双方战斗单位的差异,我们给它们设置不同的颜色。
虽然从显示方式来看,战斗单位与地图格子并没有什么差别,可是如果从数据角度出发,两者的差别可就大了。为了更好的介绍战斗单位,让我们从上至下来梳理一下整个战场与战斗系统吧。
|战场与战斗信息
一个战场就是一场完整的战斗。每一个战场目前都包含三大部分:战场地图、对战双方以及战斗过程。
战场地图
地图在之前的文章中已经做了说明,这里不再赘述。
对战双方对战双方的单位是战斗组,这里用战斗组编号区分各组,而不是仅用两个枚举来简单表示,是考虑到有很多组同时存在且同时对战的情况。
真正发生战斗的被称为战斗单位,每个战斗组由若干战斗单位组成。战斗数据、战斗组与战斗单位之间的关系如下图。
战斗打响时,从两个战斗组进入战场,到双方轮流移动、攻击,最终分出胜负,发生的一切事情,都是战斗过程,这个后面会详细说明。
|战斗的流程
战斗流程包含了战斗的核心逻辑,是战斗能正常进行且完成的规则,我们用下图来描述一场战斗的基本流程。
|将数据与显示分离
这里还是采用了将数据与显示分离的处理方法,先看一张数据处理的流程图吧。
图中很关键的一个内容是战斗过程数据,上面提及它其实是包含了自战斗单位进入战场,到战斗最终完结之间的所有过程数据。
其实,当开始一场自动战斗时,战斗计算器会瞬时计算完整场战斗的过程及结果,但这些结果只是数据,并没有呈现给玩家。
当我们需要把这场战斗呈现出来时,把这份数据传递给一个对应的显示(播放)器即可。就好像后端和前端的分工一样,一个负责产生数据,一个负责将数据呈现。
|顺序分步呈现数据
我这里使用手机号拍卖平台协同函数(Coroutine)的嵌套来分步呈现战斗过程。
战场显示器开启逐步呈现战斗过程(战斗单位的行动)
战斗单位显示器根据自己的动作数据呈现具体动作,如:
进入战场
选择目标并移动(青色框:发动攻击方,黄色框:攻击方的目标)
选择目标并攻击(青色框:发动攻击方,黄色框:被攻击方)
|分离的意义
走吧,走吧,人总要学着自己长大。
人是这样,数据也是。
其实直接使用一个继承与MonoBehaviour的脚本,把各种需要的数据都装在里面,直接挂在Prefab上,然后用一个控制器一边算一边呈现给玩家,实现起来非常容易。
但是,考虑到后台可能有多场战斗同时在进行;且后期可以在短时间内进行多场战斗、收集数据来做战斗数值平衡。将数据分离,让数据可以自行计算,就变得十分重要了。
|写在最后
至此,添加对战双方篇就介绍到这里,详细代码可以移步Github下载。
感谢您能读到这里。
愿不忘初心。
下回见。