一个MMORPG的常规技能系统

转载自:http://www.gameres.com/729192.htmlhtml

广义的的说,和战斗结算相关的内容都算技能系统,包括技能信息管理、技能调用接口、技能目标查找、技能表现、技能结算、技能创生体(buff/法术场/弹道)管理,此外还涉及的模块包括:AI模块(技能调用者)、动做模块、寻路/移动模块以及人物属性和伤害数值结算等。

先说下技能模块每一个部分的职责和原理:

数组

  • 技能信息管理:管理unit所拥有的技能以及技能的等级、cd等。在咱们游戏中,这里还须要负责管理符文,符文会对技能信息进行修改。
  • 技能调用接口:AI或者UI操做触发技能,触发技能时可能选择了一个目标(AI),也可能并无目标。
  • 技能流程管理:一个技能可能由多个子技能以移动的执行模式组合而成,而每个最终执行的技能执行过程也存在一个流程,通常包括:前摇过程-结算点-后摇过程。技能在前摇结束时进入技能真正的结算流程,结算流程可能建立子弹,也可能触发buf或者建立法术场。
  • 技能目标查找:若技能触发时已经设置了技能目标unit(如怪物AI释放技能),则直接将其做为目标unit,不然须要根据必定的策略选择一个目标。此外,技能释放的时候还须要释放方向和释放位置等信息,也经过这个模块获取。
  • 技能表现:技能释放过程当中,须要建立相应的特效以及执行相应的动做。
  • 技能创生体(buf/弹道/法术场)管理:buf挂在unit身上,可能影响unit的一些行为和状态;法术场通常由场景管理,影响场景中某范围内的unit;弹道就是技能建立的一个子弹,这个子弹可能以不一样的路线移动(直线/抛物线/直接命中等)


一、技能表

首先说下实现技能的基本思路。实现技能的基本思路就是经过策划填写表格,来配制成某些技能,在执行某个技能的时候,分别去根据这些表格中的内容,肯定技能如何表现。基本的逻辑是:数据结构

  1. if skillTable.get("技能动做"):
  2.      paly 动做
  3. if skillTable.get("特效"):
  4.      播放特效
  5. if skillTable.get("法术场"):
  6.     建立法术场
  7. ....
复制代码


二、技能信息管理

unit建立时,此模块管理unit可以使用哪些技能,好比游戏中玩家能够选择使用哪些技能。

游戏中技能的升级、技能加点、技能池管理都在这个模块。

此模块还须要管理技能等级/符文/装备等外部模块对技能参数的修改。

三、技能调用接口

提供技能调用的接口供AI或玩家操做调用,调用时能够提供一个目标unit,也能够不提供让技能本身查找。

提供三个接口:

优化

  • 技能开始skill_enter:开始执行技能,若技能不循环进行,则技能能够自动结束。
  • 技能结束skill_exit:有的技能不能本身结束,好比某些循环技能,对于循环技能玩家能够按住按钮一直释放。当玩家松开按钮,调用技能结束接口,告诉当前技能使其结束,此时技能到达后摇点时,技能再也不继续执行。
  • 技能中止skill_stop:当技能被强制打断时,如被攻击、晕眩、蓝不足等,技能会被强制中止。


此外,当前一个技能正在执行时新的技能调用启动,此时新的技能调用信息会被保存。通常来讲,并不会把全部新的技能调用信息保存下来,那样就成了一个技能执行的序列。咱们游戏仅保存一个新的技能调用信息。

总的来讲,技能模块提供尽可能少的接口供AI/UI等上层逻辑使用,这样能够有效的与AI和UI进行解耦。

四、技能流程管理

技能流程这里分两点讨论:

(1)一个技能可能由多个子技能以必定的模式组合起来。

一个技能经常由多个子技能以必定的模式组合而成,好比三段击、好比冲锋斩(先冲锋、后斩)等,甚至还存在根据不一样的环境选择执行不一样的子技能。分析策划需求发现,技能能够分红一个树形结构,这个树形结构很是相似行为树,一样能够将节点分为控制节点和执行节点,甚至能够包括condition节点。为此,咱们项目引入一个技能树概念来描述这种数据结构。

(2)一个具体的技能(技能树执行节点)也有一个固定的执行流程。这个流程通常为:前摇过程、前摇过程结束=技能结算时间点、后摇时间点。

4.1 技能树

技能树参考传统行为树的设计,使用树形结构控制技能的执行流程。

技能树和行为树在结构上比较相似,可是在运行逻辑上有很大的不一样。

首先,技能树的重点并非根据上下文选择一个合适的节点执行,而是以必定的策略将技能树从头至尾遍历执行一遍。

其次,技能树没有tick的概念,而是基于回调的,好比一个顺序节点,顺序节点中一个子节点执行完毕后,立刻通知顺序节点,顺序节点执行下一个子节点,直至顺序节点的最后一个子节点执行完毕,顺序节点就会通知父节点(若是有)它已经执行完毕。

此外,为了完成技能的一些需求,控制节点每每存储更多的控制信息来控制子节点的执行流程。具体的信息根据策划需求设置,好比顺序结点包括原子属性和循环属性。若是一个顺序节点具备原子属性,则这个顺树节点在执行的过程当中并不会被end,只有所有子节点执行结束才能够end。

以咱们游戏中战士普攻三段击为例:

spa


三段击自己是一个顺序节点,当技能开始时,此节点顺序执行三个子节点。对于第一个子节点,它依然是一个顺序节点,首先冲锋至目标单位身前,而后对目标单位进行挥砍。可是冲锋节点还包括了一个condition,若和目标的距离很近,则跳过冲锋节点,直接挥砍。

普攻是一个循环技能,这个技能只要玩家点着按钮不放开,技能就会一直执行,所以根节点(普攻)是一个具备循环属性的顺序节点。而对于子技能1(控制节点),他是一个具备原子属性的顺序技能,即当单位正在冲锋时,玩家松开按钮,单位也会执行完挥砍后才会推出技能。

!关于技能树的使用和思考

技能树开始的设计思路是,有些技能的执行流程和行为树相似,好比以必定的顺序执行一系列子技能,好比根据不一样的上下文肯定技能的执行流程。简单的说,技能树的引入有如下好处:1.使技能模块能够得到部分AI的能力,从而将和技能强相关的AI逻辑放在技能模块使技能模块和AI模块下降耦合,2.能够清晰的描述技能流程,3.使用树增长拓展性,策划能够设计出各类各样复杂的技能。

关于好处1,举个例子:屠夫boss的勾子技能能够将玩家拉过来,若成功的拉过来,boss会执行一个攻击子技能,不然不执行。经过这样能够将勾人和攻击做为两个子技能构成技能树,攻击子技能有一个condition过程,即判断上一个子技能是否成功。

技能树在使用后慢慢发现一些问题,首先,技能树的同步要求每一个树节点都进行同步,增长同步负担,其次,技能自己并不会有太复杂的控制结构。

为此,后来咱们对技能树进行了优化:

设计

  • 简化同步信息,再也不同步全部节点的enter/exit信息(具体参考文章《技能模块的同步》)。

 

  • 取消并行节点,经过拓展表头实现一个技能同时执行多件事情。


最终的技能树基本上是只有顺序/随机两种控制类型节点,节点拥有较轻度的condition功能。

4.2 执行节点的技能流程

通常来讲,技能的执行流程包括:

前摇时间:技能开始,可是技能真正的结算流程还没开始。技能开始之后,机能相关的特效和动做就开始播放。

前摇时间结束:技能前摇结束时技能开始真正的释放以及结算,等技能前摇结束之后,技能真正的释放并结算。释放包括建立相应的弹道/法术场和buff。

技能后摇点:技能播放到后摇点时间时,技能真正的结束。这时,技能对应的特效以及人物动做可能还会继续播放,可是技能流程已经正式结束了。也就是说,下一个技能能够执行。

五、技能目标查找

技能释放时,目标可能已经由AI传给了技能模块,也有可能没有一个目标,如玩家控制单位。

技能在释放法术场、弹道的时候,重要的是技能的方向而不是技能目标通常来讲,技能得到一个目标对象之后,技能的方向就是释法者到目标的方向。

此外,技能方向可能须要一些配置,如前摇锁定(前摇过程当中目标移动,技能方向不变),UI可控制(技能释放过程当中,玩家能够经过控制UI控制技能的释放方向)。

六、技能表现

技能的表现包括动做、特效、shader、音效等。其中,特效比较复杂,须要配置的内容也比较多。好比,有些特效挂在模型上,有的特效挂在场景里。对于法术场的特效,分别能够分为法术场开始、结算、结束特效,分别在法术场开始时、结算时、结束时显示。对于buff也相似。

七、弹道、法术场和buff等技能创生体

狭义的来讲,技能只是负责技能的执行流程(技能树管理以及技能流程管理),而技能真正的结算主要是由其创生体结算的。当技能前摇结束开始生效时,技能建立相应的弹道和法术场,法术场弹道击中敌人时又有可能产生相应的buff。

通常来讲,法术场是一个场景的某块检测区域,每隔一段时间法术场检测此区域的敌人,并对其攻击结算。

弹道是一类子弹移动路径的抽象,建立一个弹道就表示一个子弹特效沿这个弹道移动并检测路径上的敌人。

buff就是挂在单位身上的一个具备持续时间的状态,状态对单位产生一些正面或者负面的影响,而且在此段时间内,每隔一段时间进行一次伤害结算 。

对于技能、法术场、buff之间的功能界定并非很固定,好比技能可否直接对单位形成伤害,法术场可否对单位形成伤害,甚至技能只能建立法术场,法术场只能检测目标不能形成伤害,只能挂buff,而全部的伤害都是经过buff来结算。固然,这样并不必定好,通常来讲,技能和法术场均可以对单位形成伤害。

总之,创生体功能的界定须要根据策划需求、效率考虑等因素调整。

7.1 Buff状态

Buff就是挂在单位身上持续必定时间的有益或者有害的状态,这里状态=buff。

Buff模块有个须要注意的是Buff之间的相互关系,如排斥(A状态在,B状态挂不上去),清除(A状态挂上去同时致使B状态消失)等。

为了实现以上功能,最简单的方式是在状态A中直接填写状态关系状态字段,如状态A排斥状态B/C/D/E...,A状态清除状态X/Y/Z...。

以上的实现方式有个问题,等游戏作到后期,咱们有成千上万个buff状态,那么一个魔法免疫状态,策划须要填表的排斥状态可能成千上万。

为了解决这个问题,可使用分类的思想解决。定义某类状态和另外一类状态之间的规则。

基于以上思想,引入一个叫buff原子状态的概念,原子状态表示一类状态,如减速、禁魔、魔免、悬空、晕眩、变羊等等等。

在给单位挂一个新的buff的以前,查询此buff持有的原子状态和单位身上已经有的原子状态之间的关系,根据单位身上已有的原子状态断定新的原子状态应该使用何种行为处理。

此处的何种行为,表明的就是原子状态之间的规则,如排斥等。这些规则可让策划填一个名字叫“原子状态关系”的表,此表是一个n*n的二维数组,n为游戏中全部的原子状态的数量。

原子状态的数量远远小于buff的数量,因此能够很容易的定义这些规则。

7.2 法术场

法术场描述对一块区域的影响,这块区域能够每隔一段时间进行一次检测,检测这块区域内的单位而且对单位进行结算。

法术场须要注意一个问题,就是一个法术场每次结算可能使用不一样的参数进行结算,好比一个技能,第一次结算对每一个单位进行晕眩,第二次结算对单位进行伤害。

解决这种问题比较直接的方式是技能直接建立两个法术场,每一个法术场结算一次,第二个法术场建立具备延迟时间。可是这种方式有个问题,有可能策划需求作一个结算十次并且每次结算的参数都不一样的法术场。那么,一个技能以必定的时间间隔建立是个法术场,同时法术场的管理具备必定的成本,从而致使效率的下降。

为解决这个问题,咱们优化了法术场结算的实现机制,增长了一种新的法术场:序列法术场。这类法术场策划能够配置法术场每次结算之间的时间间隔以及每次结算所使用的法术场参数。code

相关文章
相关标签/搜索