回合制-战斗机制-实现分析
记录一下,想到哪里写到哪里。
回合制游戏一般流程是
一定时间内等待玩家输入,服务器计算该回合战斗数据,客户端收到数据后进行画面表现。
以此循环到战斗结束.
设计难点在于服务器返回怎样的数据结构,既简单又实现方便,数据量小,等具备常规工程化的特点。
梦幻举例:
1.对于一些概率性的技能等,输出肯定是一个确定的,比如触发or未触发。
2.对于伤害数值,输出的是一个具体数字,包含暴击,等相关信息。
方案1:
数据格式如果基于招式(技能,平A也可以看做是一个技能)的话,那么每个可攻击单位的每次攻击行为的数据可能像这样
对于一次完整的战斗,可达20个单位,每个单位的每次攻击大约是 220字节,一个回合大约就是4kb的数据量,最大上限可能是9kb。对于一个10回合的战斗,将会是40kb,还没包括玩家信息召唤兽信息等数据
官网找的一个录像帮战5回合,
每个 回合攻击序列都是这样一个SkillAction数组,依次播放,这样做存在的问题。是如果有技能是和该攻击行为有交互,比如反震,那么就很棘手了。方案1 pass
方案2:
根据方案1的缺点,方案2做了如下改进,客户端参与战斗逻辑处理,对于数值,几率等是服务器发送的,其余都可以是本地产生的结果。就算出外挂也只会影响他本人的体验,关键数据都是在服务器。这样的话,同一个技能,对应的数据客户端和服务端可能就很不一样。
异步战斗,战斗在开始前战斗结果服务器已经产出,客户端只需要模拟展现出画面即可,和上面的方案2一样,甚至伤害数值服务器也不用传递。只需要传递概率性 已经确定的东西,比如迷你西游,所有技能和写天赋等都是概率,服务器只需要演算,输出战斗结果和概率事件即可,客户端 演算的时候就按照 该局游戏数据的快照,比如装备信息等,就可以模拟出整个游戏了。
之前做的一个小游戏三国志OL就是采用的这种方法来自动回合战斗。这种方案的一个缺陷就是客户端和服务端都要关心某个技能的实现,主要差别只是在概率上,
三国志OL的实现,完全是概率和堆数值,每个单位有一次出手机会,并且要么是普攻要么是释放了技能,复杂度小很多,像迷你西游这种,每个单位攻击可能存在反馈,比如你攻击了某个单位,那个单位发起了反击。这种情况就稍微复杂。在这种放下下,数据可能是这样
这种从上往下从左往右执行的顺序树形结构,关于动画等延时,完全由客户端自助做主,因为他自己知道这个是什么技能,逻辑是什么,关于具体实现还可以参考行为树的框架部分XYGame-AI设计4-行为树-第2版本 达到攻击多个目标群体攻击等特点,每个动作的类型可能是这样
这种的话无论是半自动还是全自动的回合战斗,都可以用这种数据结构表示。当然了,对于客户端也参与战斗演算的话,就可以不需要行为树那一套框架来,直接是上上图哪种即可,因为客户端本是知道哪些技能是并发那些技能是串行。那些技能有什么效果,都可以推演出来。
如果客户端不参与技能的部分逻辑,那么可能就要包含一些具体的事件了,
例1:比如某次攻击中A发起对B技能1,刚好走到B面前,砍了一刀,这时候受到了反震效果:。这个反震效果实在技能1逻辑执行中发生的。
例2:在技能1发起完毕,回到站位后,B对A发起了反击。这个是在A行动完毕后执行的,这个没什么问题。
例3:在B面前准备砍一刀时,队友触发了保护,站到B面前,A砍下了,队友受到伤害。
这类技能执行期间加入了复杂的其他技能或者逻辑。如果客户端不想参与技能的部分具体逻辑的感知,那么就可能通过配置表去配置这些技能的关键执行点或者执行逻辑的组合,即达到添加或者修改某技能的逻辑组合或者数值组合,只需要修改配置表即可,
处理手法1:对于这种都是 有很强的顺序性,如触发了反震肯定是因为你的攻击,或者是反震除了概率性的前提条件,因为服务器给你的不是概率而是一个释放or未释放,存在一定的因果关系。所以在执行一个技能前就需要预读下一个技能或者行为是什么,看看他们有没有关联,
相当于一次读取2个技能,先判定他们之间是否有关联性,比如反震,肯定是在砍了之后触发。这种切入时机也可以配置表配出来,可以是3个截断,技能释放前,释放中,释放后。但是这样局限于了1对1技能的交互,按照服务器的验算逻辑序列化来看,顺序应该是这样
对于技能1触发了2个技能,是平行关系,他们可以有一组加权判定到底谁先执行 谁后执行,当然也可以直接按照顺序来播放,因为输出序列服务器可以是按照序列来输出的,客户端只需要吧服务器输出的关键信息播放即可。这样方式看来还是绕道行为树的那种框架去了。上图就是一个顺序节点。
一次1V1的战斗服务器输出的动作树可能是这样,这几乎和行为树没什么两样,因果关系用子树表示即可,看起来很好实现,可能和树型结构天生适合处理复杂的组织关系吧。
图中的Action节点的数据可能是这样,当然也可以用命令cmd的方式来驱动
在做录像的时候只需要吧这颗树保存下来,以下几种情况:
1.如果要能够跳转任意回合前跳后跳,因此每个回合之间不能有耦合性,每个回合初始都有一个当前战局的快照,就可以保证每回合相互独立。
2.如果要只能快进或者往后跳转,那么1的快照就可以省略,改为初始回合的快照即可。当然这样做肯定体验不好,多用点数据实现1也是没问题的
2.版本变更导致的技能或者逻辑的冲突,如果客户端知会了具体逻辑的话,那么将会出现严重的录像系统版本问题,情况更为复杂,
//——————以上分析是针对梦幻西游的半自动回合(每回合可以下达战斗指令,从而改变战局等要素),又或者是迷你西游的全自动(法术什么的都是概率释放,整个战斗过程完全异步,客户端开始前结果服务器就算好了),这种的buff debuff等都是基于回合的。称作模式1吧。
//—————–如果战斗模式按照回合,但是技能 buff等是按照时间来的,中途没有固定最大时间等待玩家输出的操作指令,这种有点偏动作MMO类型的操作方式。只要技能释放完成就可以下达下一个指令,而不同等待对方也攻击完成后才统一等待指令。称作模式2吧
区别在于传统的是基于回合的,对于时间点就只有和服务器的交互也局限于每回合的等待玩家操作指令,其余时间都是可以由客户端自由操控,比如加速播放 等,而模式2 的cd要么按照传统的MMO做法,客户端一套cd 服务器一套cd,他们关联起来当做一个状态来处理
基于模式1的那种类似于行为树的结构要引入cd状态,这个引入点可以是每回合的开始节点的快照信息包含了cd,客户端根据时间自己做插值,当然录像的话也是相同的手法,下回合又有新的cd状态,用于cd数据的修正,在这里需要特别考虑一下网络延时给cd修正带来的影响。
如果不把cd状态嵌在回合快照里面,而和一般的MMO做法一样单独采取一些消息手段 单独处理,也是可以的,因为这种回合没有中断,始终是在播放,游戏一直在推进,如果你按下了技能就释放没按下那就平A,这种的设计对于录像就不友好了,要么在另外做个这种消息的快照,要么录像模式下直接不显示cd,又或者客户端自己模拟一个cd,因为技能的cd时间客户端是可以通过配置表知道的(但是这种方式不适合配置表不能准确判定cd的情况下,比如某技能减少全局cd 50% 又或者是某药品立刻冷却所有cd,如果客户端不想感知具体逻辑的话,这种方式就不适用)。等等方式
接下来就是吧上上图的树形关系解析为一个一个的动作了。之所以采用树形结构,是因为他们的因果关系,普遍来说,这颗树的层次一般不会很高,宽度和执行了的单位正相关。遍历一次树生成一个个动作序列,客户端的
逻辑处理器只需要按照生成的动作序列,逐个执行即可,当然因为 一维的信息,因此要加入一些约定好的固定操作,比如顺序节点,表示依次往下一个一个执行,遇到节点结束节点 才停止当前顺序逻辑,比如并行节点,那么一次处理遇到结束节点之前的所有节点,比如某个药瓶回血回蓝,2个可以一起提示出来。又或者是反震技能和反伤技能一起发挥作用,总之和顺序的递进处理 不一样
每遇到一个结束节点表示一个因果关系的结束。每个因果关系的序列的父节点,总是导火索。比如上图的,B对A使用了反震技能,的导火索是A对B使用了技能1.,
每个节点的状态可以是以下3中,Running 1 2 只是扩展出来的, 有没有用还是要具体分析游戏逻辑的需求,这个和行为树的行为节点的状态很像。比如反震效果是在玩家攻击后,还未回到站位前,在这里当做Running2 处理,触发的,而保护技能是在玩家走到目标前面,还未砍下去触发的,因此各个因果关系的果就有必要配置出在其父节点的什么状态下切入。这样的话又回到之前说的一个 配置的准确性问题,比如策划有个这样的需求,如果好友度达到了1W 那么就可以在开始节点执行保护。这样的话那还和版本有关系。录像能不能准确播放也会是个问题
上面几个问题的根本原因是由于各个粒度嵌套很深的关系中,信息,要么全部服务器发送,要么一部分信息发送,那一部分的没有发送的信息,会由客户端通过一些手段(比如读取配置)如果存在更改迭代,那么就会出问题。这样来看的话,那就比较好解决了,由于录像信息可以是客户端生成的,在生成的时候也把这些未发送的信息快照一般记录在内,这样的话,录像播放机就完完全全是个播放器了。如果客户端知会了一些具体逻辑的代码而不知简单的配置的数据,那么这种做法就不行了,代码片段你不能保存以供录像用,虽然想这么多也可以,弄成脚本,但是问题由来了,前提是脚本涉及到的非脚本代码能够兼容。这简直是个恶性循环。
TODO