战斗系统设计概述

2017-07-20  本文已影响0人  小星星幼儿园
同步方案:

在同步方案上采用的是状态同步的方案,主要的考虑是状态同步是网易多款实时手游均采用的方案,得到了验证,风险性较小。客户端接受用户的操作输入发送给服务器,所有战斗逻辑在服务器计算完成,服务器将客户端表现指令发送给客户端执行。其中,为了精确匹配远程攻击和相应扣血,所有的远程的扣血由客户端判定命中后向服务器请求触发。

代码架构:
战斗代码结构

battle.lua是整个战斗逻辑的最上层。battle.lua处理消息的接受和分发、战斗的主逻辑think的执行,战斗开始和结束的管理。

fighter.lua管理每个玩家的行为和卡牌状态。

base_entity.lua、entity.lua、entity_moveable.lua、tower.lua、arrow.lua、...等等是各类Entity的类,他们之间有继承关系,处理Entity状态机。

battle_base.lua是处理所有战斗的基础功能类,功能包括Entity创建、Entity选择、Entity管理、Entity死亡处理、数学运算处理、寻路入口。

battle_net.lua是处理所有战斗消息的发送。

skill_base.lua是处理所有技能的释放,skill_.lua以及buff_.lua是所有技能和buff具体的实现。

astar_path_find.lua和collide.lua分别处理网格注册管理、Entity碰撞。

AI:

(1)在人人的PVP战斗中,两方玩家只需要将单位拖动到场上,上场后单位由AI托管。每个Entity的AI采用状态机的方式来实现。Entity的Think函数在每帧中:1. 判定state是否满足转化条件,如果满足进行state的转化 2.执行state内的行为。Entity的主要的state包括:fixed、idle、ahead、walk、run、attack、pursue、dead、skill。

(2)在人机的PVP战斗中,有专门的机器人AI来模拟玩家的行为。首先,机器人在选牌阶段,会尽量保持牌组的均衡,避免选出过于极端的阵容,具体的做法是会在可选的牌中选择一个攻击评分top2、防御评分top2的卡牌,然后随机选择剩余的牌。战斗中,AI每隔1s会进行一次think,每次think只会产生一次操作(为了模拟人类的思考间隔)。采用行为树来实现具体的think,如下图所示。

行为树

另外,在选择了要放置的卡牌之后,它的放置位置的选择也比较重要。位置选择的主要原则有:(1)进攻时,围绕英雄或者聚集式放置单位(2)防守时,根据对方的来犯单位放置单位。英雄的技能的自动释放也由AI机制进行管理,它的触发由独立的逻辑判定触发,会根据当前场上英雄的技能的特性判定是否到达最佳的释放时机,然后决定是否释放。

(3)PVE战斗怪物和Boss的AI触发条件和行为比较复杂,每个副本都需要可配置具体的AI,采用的ACT(Action、Condition、Trigger)方案,可以支持比较灵活的AI配置。每个怪物和Boss都可以配置多条ACT逻辑。它们的think函数每帧判定自己的ais里是否有Trigger被触发,触发后判定Condition是否通过,通过则触发Action。

技能和buff系统:

由于我们的游戏技能设计比较复杂,技能和buff系统是整个战斗最重要也是最庞大的部分。

从释放方式上来说,分为:

main_skill        --普攻技能
init_skill        --出生直接释放一次的技能,没有技能动作
birth_skill      --出生自动释放一次的技能
auto_skill      --自动释放技能
manual_skill      --手动释放技能
dead_skill        --死亡释放技能
init_buff        --出生自带的buff

另外,技能可以拥有子技能(主技能释放时会触发子技能的释放)、计数技能(根据使用次数触发的替代技能)。

技能的具体类型分为16种:

attack =1,      --攻击
create =2,      --召唤
move =3,        --位移
buff =4,        --buff
field =5,      --法术场
dispel =6,      --驱散
taunt =7,      --嘲讽
heal =8,        --治疗
field_arrow =9, --移动法术场
field_aura =10, --光环
evocate =11,    --复活
energy =12,    --回费
purge =13,      --净化
gather =14,    --聚人
transfer =15,  --传送
push =16,      --推人

buff是技能系统的重要组成部分,具体类型分为19种:

fixed =1,      --定身
perporty =2,    --属性
attack =3,      --伤害
heal =4,        --治疗
soul_link =5,  --灵活链接
trigger =6,    --触发技能
power_scale =7, --系数
disapear =8,    --消失
dead =9,        --定时死亡
stealth =10,    --隐身
immune =11,    --免疫
subdue =12,    --征服
follow =13,    --跟随
absorb =14,    --吸住
suck =15,      --吸血
dying =16,      --垂死
protect =17,    --护盾
ability =18,    --基础能力
accum_power_scale =19, --累加系数

技能的释放过程包括选择目标、对选择的目标释放技能。选择的类型包括:

RANGE_TYPE= {--主类型
single =1,      --单体
circle =2,      --圆形
rect =3,        --矩形
self=4,        --自己
sector =5,      --扇形
focus =6,      --当前目标
}
SUB_RANGE_TYPE= {--子类型
random =1,      --随机
closet =2,      --最近
exclude_target =3,--除了当前目标
}

选择目标的时候会采用主类型和子类型结合选择出目标。另外,还支持一些特殊类型的选择目标需求,包括:

SPECIAL_SELECT_TYPE= {
random =1,      --随机
random_buff =2, --筛选buff
random_hp =3,  --筛选hp
random_type =4, --筛选目标type
}

以上是对技能系统的概述,还有很多细节,这里不做过多的讨论。

寻路碰撞系统:

寻路系统随着地形的需求不同做了几次迭代,也陆续实现了几种寻路方式,最终地图采用了无路障的方式,也就抛弃了寻路系统的使用。这里还是说明一下我们在寻路系统上做的一些工作。最早,实现了astar的寻路算法,astar的优点是能够解决动态碰撞的问题,缺点在于计算量比较大(有考虑过预先bake路线)、路线比较直有明显的走格子的痕迹。又尝试了导航网格的寻路算法,对于我们的障碍物比较大块的地图来说,导航网格对地图的划分比较少,计算量相对于astar算法会比较小。另外,导航网格寻路的路线比较自然。但是它不能解决动态碰撞问题。

碰撞系统在效果上是要模拟皇室冲突兵种单位之间推来推去的效果。网上没有现成的库可以用,我自己实现了一个算法。在设计这个算法时,最担心是性能问题,所以整个算法的出发点是如何降低性能开销。首先,我们把整个地图划分为1x1的格子单位,这个大小和我们的单位的直径比较接近。单位在移动的过程中会更新自己的所在格子信息。单位移动时会触发一次碰撞处理,根据自己当前的格子以及移动的方向,确定有可能产生碰撞的单位所在的格子,然后取出格子中的单位做碰撞处理。一个单位被碰撞后会产生位置的移动,会发起一次子碰撞处理,这是一个递归的过程。这个过程不加特殊处理很容易陷入死循环,我做了约束,一个单位在一次碰撞处理中,只会被移动一次。这个算法在实际使用中,发现有些速度相同的单位叠在一起后,会陷入互相挤压无法分开。为此,我加了一个简单的处理,判定两个单位是否处在重叠状态,如果处在重叠状态,会直接强制拉开。经过反复的算法调整,目前效果没有出现比较明显的问题。

天梯匹配的机器人难度控制:

在游戏测试时,由于玩家的导量不足,需要有机器人去模拟玩家跟玩家作战。机器人有两大问题,第一就是如何尽可能的模拟玩家去作战,第二就是如何给玩家匹配一个水平相当的机器人。这里主要讨论第二点,如何给玩家匹配水平相当的机器人。其他游戏有很多可以参考的做法,比如经典的war3、dota。一般采用的方法分为两类:1. AI分级 2.获得钱的速度分级(属性分级) 。AI分级比较难,而且很难做到天梯这么多档次的分级。属性分级相当比较容易线性的调节。我们主要的做法是通过属性分级来做。我以玩家和机器人作战的胜率作为算法的核心目标,为了让玩家打电脑没有那么强的挫败感,我们定的胜率是65%(是下一场的期望胜率,不是总体胜率)。这个胜率作为权重计算出玩家对电脑的净胜场数。我们将电脑的难度分为上下一共20个level,每个level对应一定的属性加成或者减少,根据净胜场数得到对应的level。

净胜场是比赛机制中常用的用来判定水平的标准、另外一个判定水平的标准是胜率。

上一篇下一篇

猜你喜欢

热点阅读