有人的地方就有江湖,游戏里也一样。无论为了什么目的,游戏中的人也被无形分出了三六九等,于是各个游戏角色站位就有了讲究。于是乎,就有了今天的问题:当大家都是有身份的人的时候,怎么移动最能体现这种地位?
其实这个问题是因为最近做的项目而来。游戏类型算是一种RTS,而且还需要结队行走,所以这里就有了需求:整个队伍按照阵型移动且过程平滑。
今天就用一字长蛇阵来聊聊这个话题吧!
一字长蛇阵就好比开火车,火车头走自然带着车厢一起走,而且走的过程当中车厢并不会打乱顺序,所以很符合我们的需求模型。不绕圈子,下来就说说几种实现方式吧。
1.以车头为原点,计算得出其他车厢的位置。
这种方法应当是比较常见的一种,即在确定了车头的位置和角度后,沿着反向通过车厢间隔就可以确定每个车厢的目标位置。在确定了位置之后,可以在游戏中让车厢瞬移到目标位置并调整方向,也可以让车厢平滑向目标点移动,并实时更改车厢角度。
好处:计算简单啊!二维空间下知道一个点和点的方向,计算反向固定间隔的某点简直易如反掌。而且模型的理解成本低,实现也简单。
坏处:根本不符合需求啊!有人见过车厢瞬移的吗?火车是一条直线,车头一旦发生转向,整个火车就以车头为原点进行了旋转,视觉上就给人一种打死程序的冲动。即便让车厢平滑移动,也无法保证视觉上车头车尾的首尾相连,更何况转弯大点的时候还有可能出现车厢交错的情况。所以在当前需求下,这种情况被pass。
2.以每一节车厢后向某固定点作为下一节车厢目标点。
这种方法是第一种的变种,为了破解僵硬而存在。具体操作就是让车头后固定某点作为车厢1的目标点,然后在得出车厢1的坐标与方向后再在其后固定某点作为车厢2的目标点,依此类推。这样做的好处自然不会让火车永远是一条直线,随着车头转弯,车厢1随即移向目标点且自身产生旋转,由于旋转的叠加效应,后续车厢自然使整列火车变成了一个弧形。这种情况下,瞬移也会有很好的效果,相较方案1避免了多数叠加的情况。如果平滑过渡自然表现会更好。
好处:火车终于不再僵硬,因为每一节车厢的旋转都是依据前一节车厢计算而得,因此这样得到的结果本身也更为平滑,已经很接近需求。
坏处:计算量加剧,如果车厢多一点,则每一次都需要计算车厢的方向是一个性能消耗点。虽然移动更为平滑,但是在瞬移模式下,由于旋转由叠加而成,因此旋转方向一旦发生变化,末端的车厢会发生较大距离的位移,因而产生失真,依旧不适合当前需求。
3.以每一节车厢为后一节车厢的移动方向,根据间隔距离计算目标点。
这种方法以方法2反向而得。具体操作就是车头移动,然后车厢1向车头移动,且保证车厢1与车头的距离等于两者原本的间隔,然后车厢2向移动后的车厢1移动,且保证二者距离不变,依此类推。这种情况下我们可以计算得出,只要某一方的瞬间旋转的角度不超过阈值,便可以保证不失真(阈值的计算与间隔、瞬间移动距离和方向有关,即保证A移动后与B的间隔大于A移动前与B的间隔)。
好处:最贴近目前需求。移动不再僵硬,解决了左右旋转瞬间可能产生的失真,即便使用瞬移也可以使视觉效果顺滑。
坏处:与方法2计算量基本一致,如果以火车模型说明问题,则车厢之间连接处还是有错位的失真,只是这种失真较之前小很多罢了。
小小的总结下吧
目前尝试了这三种,不排除还有其他的方案,比如逐帧记录运行轨迹然后复原等。总体而言,以上三种如果说对于火车这种首尾相连要求苛刻的模型,则都会有失真的情况,但如果只是比照火车运行轨迹,则方案3更为平滑符合要求,方案2则由于运行速度、旋转方向等关系使用条件较为苛刻,方案1则让扔到垃圾桶里了。不过要说明一点,方案1作为计算量最少的方案,在一些类似小小兵团这种多人物阵型的游戏中还是很重要的。只是在人少的情况下,为了视觉的舒适,我们菜肴探索方案2、3这一类方案。
其次,以上三种方案对于渐进模式,都存在失真的可能。一旦旋转角过大而移动速度不足,则人物移动当中的重叠等就变得不可避免。因而在上述的几种方案的基础上,还需要一些其他的设计来保证人物移动的真实感。
那么我在项目中如何实现?
现有项目基本采用方案3。但是对于我们的项目而言,方案3也仅仅是第一层。首先需要明确的就是我们的阵型并非单纯的一字长蛇阵,而是多种阵型,但是基本目标都是实现主角们按照阵型向前移动并转向。因此我们套用了方案3作为阵型的基本模型。在方案3之上,我们再嵌套阵型进去。比如我们的“双纵阵”,便是主角们排成两列进行移动。这种情况下,我们就按照方案3的思想创造出n/2个节点,然后将阵型当中的每2个点划归进1个节点之中。这样,当节点移动时,每个点就根据所属节点的位置与角度以及固定偏移量,计算出该点的最终位置,然后向最终位置平滑移动。