一个支持非常多种技能的回合制自动战斗系统,适合场景:挂机游戏
通过简单的编写就可以添加新的技能,如果格式足够标准,这个技能会自然的与其他技能进行化学反应 而不需要作者投入时间去处理各个技能之间的联动
buff是什么?我们最常见听说的buff是攻击力+xx% 生命恢复+xx%等等。也有人听过debuff的概念。 这里我们扩展BUFF的概念,将所有东西全部视为buff。除了上面提到的,角色的所有技能也全部以buff 形式附加在角色身上
在一些复杂游戏中,经常会出现角色玩到一半出现新技能的情况(比如大乔一开大,你就可以点击她的传送按钮)。 与其将这些技能特殊处理,不如将所有的技能都视为是后天获得的,统一管理。
buff是本系统的第一公民。
我们注意到所有buff都可以抽象成同一种结构:
如果 A 则 B。
这里前一个A是触发条件
(也可以叫trigger
触发时点
时点
,反正都是我自己起的名字),它会因为特定事件
而触发。后一个是动作
,这是一个非常大的抽象。因为它可以模拟所有游戏规则。足以容纳游戏巨大的复杂度。
具体的说,这是为《炉石传说》《游戏王》等极端复杂游戏设计的系统,包容普通的游戏结算算是绰绰有余的了。
下面我们以一个例子示范:
小明(基础攻击100)有2个buff:
- 攻击力+100
- 攻击力+100%
现在需要计算小明的攻击力,这个步骤可以在buff附加好的一瞬间就主动去进行以便后续计算,也可以在需要时再计算(懒加载),这就决定了2种不同的触发时点,这里以简单的第二种作为例子:
- 要计算攻击力了,发送
计算攻击力数据包
,里面记录了小明的基础攻击100
,要计算攻击力的人小明
- buff1触发条件:如果要计算攻击力,且计算攻击力的人是
小明
(或者说,计算攻击力的人是本buff的拥有者),则数据包内的攻击+100
- buff2触发条件,同上,数据包内的攻击力
x2
。
随着2个buff正确响应,最后数据包内的攻击力变成了400
,取出即可。
我们这里默许了小明计算攻击力时,是先加后乘,但是不同游戏攻击力计算公式有别。如果先乘后加,最后结果就是300
有的游戏非常疯狂:随着buff施加顺序的不同,结果也不同,如果变更buff顺序就会影响结果。
或者游戏默认规律就是先加后乘。这样收益是最大化的,很多游戏都这么干。
无论如何,这两个buff的触发时点是相同的,为了正确确定他们的顺序,需要一个优先级机制协调一下。
对于一些更加复杂的情况,可以强行将它们分为2个时点分别进行。
究竟何时应该计算小明的攻击力?如果一个游戏攻击力会频繁的被调用,但是修改的频率稍低,最好的选择是使用一个缓存处理。只在需要的时候刷新。
在本系统中有一个暴怒
技能,玩家血量越低,攻击力越高。这使得很难决定何时才应该刷新攻击力。(只要生命变动就得改)
讨论性能问题为时尚早。所以我没写缓存。也就不需要考虑上面的复杂问题了。
第一个例子只是正常Buff的结算而已。第二个例子会讲解技能是如何成为buff的。
其实别无二致,只需要一个施加技能
触发的事件
即可。施加技能在一般游戏里可能是玩家按下了按钮,在挂机游戏里当然是由一个死循环反复触发的。
如果 施加技能
则 开始技能结算
然后开始技能结算
里又开始调用获取攻击力``获取防御力
等等例子1里提过的很乏味的内容了
普攻也是一种技能。
- 可堆叠层数,且最大层数有限的buff,是需要考虑合并操作的。
- 有些buff会使你免疫另一些buff。
- 有些buff有持续时间
- 有些buff会往全局变量里写东西
- 有些buff会扭曲其他buff的效果
看起来只是小细节实际上每个处理起来都很麻烦。因为buff的行为只是一个封装好的函数而已, 除非去修改字节码,函数流程已经固定了,自然承受不起合并甚至扭曲的摧残,只能写一些很丑的代码放一些全局变量之类的打好补丁。
msgManager.py
是负责管理buff的地方,它负责让所有buff都在合适的时机运行。
这是个美差,因为buff已经自带了判断函数。
他要做的就是在受到消息时依次问每个buff要不要行动就行了。
这个模式可以认为是观察者模式或者分发生产模式或者别的什么。我不熟悉。
数据包也是个重点,例子1里提到了计算攻击力数据包
,实际上事件非常多样,所以真正的数据包种类繁多。
但是完全没必要写几百个数据包类,全部塞在一个里面(msgPack.py
)才是最好的。
我针对即将做的游戏进行了特殊适配,失去了一些一般性。不过可以比较轻松的调整。
目前把所有技能作为词条附着在角色身上
没有魔力,基本没有主动技能
没有日志系统
skilltest.py
里有很多战斗测试,运行查看log即可
如果对本系统是如何作用于炉石等游戏的感兴趣,可阅读https://zhuanlan.zhihu.com/p/534675937