基于行为树的MOBA技能系统:Buff系统
基于行为树的Moba技能系统系列文章总目录:https://www.lfzxb.top/nkgmoba-totaltabs/
本篇文章主要讲一下Buff系统的设计。Buff系统是战斗系统中最为重要的一个部件,我们技能效果就是依靠Buff系统实现的,比如伤害,治疗,破甲,眩晕,护盾,斩杀等,也就是说一个技能真正的核心就是组成它的那些Buff,这一点其实在《可视化节点技能编辑器的制作》一文中的示例中有体现。
这就可以引申出一个“万物皆Buff”的思想,所有的行为/效果都可以用一个Buff来实现,常规的比如一个持续伤害Buff,特殊的比如一个播放特效Buff,往客户端同步数据Buff。
指导思想有了,并且经过《可视化节点技能编辑器的制作》文中Buff系统相关介绍,我们可以知道这种方式确实可行,那么具体怎么抽象出一个健壮的Buff系统就是我们需要考虑的事情了。
本文更多的是介绍Buff系统Runtime的架构设计,Editor的架构设计可从下图得知,更详细的内容在《可视化节点技能编辑器的制作》中:
正文
基类抽象
首先我们Runtime下的Buff需要有数据载体,用于记载此Buff的数据(也就是我们在Editor下配置的Buff数据)
其次一个Buff必定是有头有主的,所以必须要有两个字段记录这个Buff来自谁,作用在谁身上,有了这两个字段,我们的Buff就可以获取所有想要的人物的数据,并且执行相应操作
然后就是Buff层数,状态这种即时数据了,所以就有以下基础字段
1 | /// <summary> |
生命周期
因为大部分Buff是有时效性的,而且在不同的阶段都有不同的逻辑,所以生命周期也是必不可少的了
1 | /// <summary> |
一个Buff被添加到人物身上后,实际上是被添加到人物的BuffManagerComponent中,BuffManagerComponent会根据具体Buff状态执行上面的生命周期函数,具体如下
1 | public void Update() |
监听Buff
之所以把监听类型的Buff单独拉出来,是因为他与常规的Buff相比更特殊一些,因为它会涉及到事件的订阅,而就是因为这个事件的全局订阅机制,我们需要做一下额外处理的
试想这样一个场景,某英雄的一个技能组成中,包含了一个监听Buff A,这个监听Buff A会订阅一个事件B,这个事件B由另一个Buff C分发,假如我们不做任何处理,一场战斗中如果只有一个此英雄,那是没问题的。但如果对面也有一个这个英雄,就不行了,因为对面英雄的Buff C也会触发事件B,这样会导致两人的技能都会响应这个事件,就乱套了。
所以我们需要为事件加上唯一性标识,我的做法是在事件订阅/分发时加上Buff来源英雄的Id,就像这样
1 | //订阅事件 |
走一遍Buff的完整流程
前面的内容比较零散,所以我来带大家走一遍一个Buff的完整生命流程
1 | //获取一个Buff,并执行Buff的OnInit自动初始化相关数据,将Buff状态设置为就绪状态,执行OnExcute |
特殊的,如果一个Buff在存在期间又被添加了一次,就会执行OnRefresh函数