先上图。
刚刚编辑好的样子:
测试了一下,每次都是在上一次fire的结果显示的瞬间再发送fire指令。可以看到,一开始的默认时间是5秒。然后加了5秒,按fire后等了差不多10秒才输出了我被fire了(因为用的是sleep来控制Tick,所以不是太精确的)。最后,dec了10次,fire就变成立即完成了。
熟悉Unreal3的应该一看就明白了,做完了节点系统后就对序列这块儿手痒了,于是忍不住就顺便把序列做了。
什么?您问我序列有什么用?不是吧……您是做游戏的吗?(玩笑)
序列系统做过RPG、RSLG这类游戏的应该都清楚它在整个游戏中的地位,没有这个东西,海一般的剧情、对话什么的得把你搞死。
序列系统基本的概念就是绝大多数的事情是不可能瞬间完成的,必须要分步骤去完成,一个步骤结束后,紧接着下一个步骤,一步步来,直到把整件事情做完。
很简单吧,想想下面这个情景,就是一个很典型的序列:
A先走到B跟前,拍他肩膀一下,然后跟B对话。同时,B被拍后,先惊讶一下,然后转过身来对着A,这时候对话已经发生了,B接着A的问题对答下去。
这中间,有Action(A走到B跟前,A拍B),有Event(B被拍),有‘线程’(A说话的同时,B这时会惊讶),有‘条件’(B惊讶完毕,且A的话说完了,B接着说下一句话)。
您说不需要序列系统,可以用状态机系统+写脚本代码来处理?成,哥您自己试试去……
……哥您好,哥咱10年后再见……
序列系统的实现很简单,每个行为作为一个单元,每个单元相当于一个小的状态,从初始单元开始,满足激发条件时,激发相应的下级单元,直到整个序列的所有单元全部执行完毕为止。概念上基本上可以视作是状态机的变种,但其实跟状态机所做的事情完全不同,在某些方面比状态机要灵活得多。
FPS游戏剧情化的今天,序列系统的作用也凸显出来,所以Unreal2里还没有的Kismet,Unreal3就提供了。
其实最早接触序列系统还是03年的时候看《圣剑群英传》的源代码,那里面的序列系统是用自己写的TXT脚本来配置的,做if之类的就需要跳转到其它TXT,结构虽然很清晰很好懂,但就是最后的TXT会成一大堆。后来的工作中也慢慢接触到了不少这方面的工具,都没有太好用的,直到看到Unreal3的Kismet。
Kismet我觉得比较好的一点是它分出了Action、Event、Variable的概念,圣3里只有A和V,没有E(记得是没有),所以整个游戏是单线发展的,游戏代码里通过操作影响V,V再影响分支,可读性……需要费点功夫。而E的加入则很大程度提供了更大的灵活性和可读性,所以这一点就被我义无反顾地继承进来了。我的系统也是EVA三者构成的三位一体,E是推动力,V是数据源,A是控制流。
客观地说,Kismet这套编辑还是把方便和强大融到一起了,问题就是最后弄出来节点一大堆一大堆,虽然可以用嵌套但是还是不是太舒服,用过的应该有深刻体会,到最后整个序列往往会失控爆炸。
目前的初期版本中,我的系统也是这样的问题,后面会增加子序列的概念,比嵌套来说略有不同吧,主要是嵌套中很难共享一些数据,Local数据、Parent数据和Global数据的界限也不是特别清楚,子序列比嵌套更像函数一些,解决这些问题应该会好办一些。
另外就是Kismet中的序列是单实例的,就是一个节点同时就是一个实例,游戏运行阶段除了那些Prefab里的Kismet外,整个游戏的Kismet只能有一套实例。优点就是这样的话编辑器可以做得很强大,编辑器里面可以跟踪每个节点的状态,也可以在节点变化时第一时刻反映到游戏里。缺点呢?就是Kismet跟整个地图耦合到一起了。其实这就是一种抉择,任何情况下,高耦合都代表着“可以用更少的代码、更简单的结构来实现更高的集成度”,同时也代表着“扩展性因此会减弱、可维护性降低”。Unreal3将编辑看做重中之重,选择这样的道路合情合理,未可厚非,如果用低耦合的方式来做,那代码量就上去了,而且对参与者的素质要求极高,成本也是一个问题啊!
而我比较想完成的是比较独立一些的序列系统,跟游戏逻辑和编辑器可以相对独立一些的,即便不想用来做游戏也是可以的这样的序列系统,所以我这里没有完全套用Unreal3的思路来做,而是把节点和实例分开了,这样一套节点系统可以用在不同的场合,而编辑器耦合地图,如果真有这种需求的话,可以做特殊的组合节点来组合节点和实例。此外,一个节点系统考虑到了在UI、物体内部、物体之间交互的多种可能性,后面应该慢慢能体现出来与Unreal3的不同之处吧。
U3的Kismet里可以堂而皇之地把X、Y、Comment这些属性写到每个序列元素的基类里,因为它知道编辑器要用到这些东西,但我的序列系统就不能这么设计,因为我的序列系统并不是必须要跟节点系统关联的。这可不是一个小问题,因为由此牵扯到存储(节点专有数据和序列专有数据)、组织(以序列来组织呢还是以节点来组织?)等等一系列问题。脱耦这话谁都会说,可是一个脱耦又能带来多少问题呢?
所以说还是需求决定设计啊!想脱耦就要有对付脱耦的决心和勇气,还要有充足的时间和自由。
所以,理所应当的,节点编辑系统和序列系统是分开的,也可以用代码组合的方式来写序列:
也就是说,做什么样的序列编辑器完全可以根据情况来进行,真想做《圣剑群英传》那样的TXT编辑反而更方便,只要觉得好用,万事好商量。
序列系统先弄到这里了,接下来准备用这套节点编辑系统来做代码生成,敬请期待《WPFLinkerNode第三弹:图形化的源代码》