类魔兽世界 技能 天赋 成就 log 系统设计
狭义来讲,技能就是几个人作战时,可以对他人使用产生一定效果的操作。魔兽世界对技能定义进行了扩展,即在魔兽世界中,产生一定效果的任何操作都是技能。例如 吃面包,使用物品,采矿,训练商业技能 等等。
魔兽世界中技能可以产生一个立即的效果(例如 扣血,扣篮,挖到一个矿),或者是一个持续的状态(buff),或者两者兼而有之。立即效果处理起来比较简单这里就不细说了,这里主要说说程序中buff怎样处理。
魔兽世界中buff简直是千变万化,估计没有人能完全的了解所有的buff的效果。这其中有很多种分类,例如
类型 | 例子 |
影响数值型 | 奥术智慧,邪甲术 |
控制型 | 变羊术 恐惧 |
持续伤害型 | 腐蚀术 |
被动触发型 | 荆棘术 |
加强效果型 | 法师的冲击天赋 |
...... | ...... |
很显然,暴雪的开发人员不可能一个一个技能去编写。那不仅难以控制代码,策划也无法脱离程序员去实现技能。其实我们根据破解魔兽世界的客户端,可以看到,魔兽的技能是一个一个配置出来的!程序员只需要做好基本的效果,之后技能就交给策划去配置了。
咋一看,buff种类太多,看上去让人头大。其实可以分解出一个共有的特点:buff是由三个部分组成的: 1. 时间 2. 条件 3. 动作。
我们分析一下上面5种类型的buff这三个特点:
技能 | 时间 | 条件 | 动作 |
奥术智慧 | 加减buff时 | 本次加的buff | 加减智力数值 |
变羊术 | 加减buff时 | 本次加的buff | 变形,减buff 还原 |
腐蚀术 | 该buff时间间隔到的时候 | 扣血 | |
荆棘术 | 被打时 | 1.近战攻击 2.命中 | 对攻击敌人释放攻击技能 |
法师的冲击天赋 | 打中时 | 1.火焰魔法 2.命中 3. %2 几率roll成功 | 对目标释放一个晕技能 |
一个动作可以是具体效果,也可以是释放一个技能
上面几个技能触发时机如下图所示:
我们可以发现,在整个技能流程中buff作用效果可以穿插在一些时间点。所以我们可以这样设计配置文件:
技能id | 时间点 | 条件 | 动作 |
奥术智慧id | 1,2 | 5 | 1,2 |
变羊id | 1,2 | 5 | 3,4 |
腐蚀术id | 3 | 5 | |
荆棘术id | 4 | 1 and 2 | 6 |
冲击id | 5 | 3 and 2 and 4 | 6 |
这里给出具体含义:
时间点:
1 加buff时
2 减buff时
3 buff tick到时
4 被打时
5 打人时
条件:
1 技能是近战
2 技能命中
3 技能是火焰魔法
4 几率roll成功
5 本次技能施放的buff
动作
1 加智力
2 减智力
3 变形
4 变形还原
5 扣血
6 释放一个技能
时间点的使用
服务器端怎么使用这些配置呢?很简单,服务器上提供一个钩子列表即可,配置文件中,时间点就是钩子的挂载点
vector<boost::signals2::signal>
比如荆棘术buff加上时,根据配置注册到事件的vector相应位置,下标就是时间点
一旦有人被攻击,就会执行下标为4 的所有事件
一旦攻击 就会执行,下标为5的所有事件
条件的扩展
魔兽世界中,buff触发的条件是极其复杂的。例如上面冲击天赋触发条件涉及到三个小条件。这还是比较简单,条件与条件之间只有and关系。如果有or关系怎么办?我们可以用一棵行为树解决这个问题,行为树可以实现and和or的关系。所以完全可以让程序员开发策划需要的condition节点,策划使用编辑器编辑行为树即可。行为树在此就不细说了,大家可以找google看看
再说天赋成就和LOG系统
看到这里,大家也明白了成就系统无非也是三点1. 时间 2. 条件 3. 动作
比如坐骑成就:
成就id | 时间点 | 条件 | 动作 |
收集50个坐骑 | 收到一个坐骑时 | 有50个坐骑 | 增加一个坐骑大师的称号 |
LOG也是一样:
Log | 时间点 | 条件 | 动作 |
记录一次转移金币大于1000G的LOG | 扣钱 | 数量> 1000 | 记录log |
魔兽世界天赋就是一些隐藏的永久buff
顺便给出一个简单实现:
https://github.com/egametang/Egametang/tree/master/Cpp/Game/BehaviorTree