编者按 游戏开发技术的学习过程,都是典型的“学习知识→分析问题→忘却之后再学习→总结经验→得出新的知识”的过程。
作者:猴与花果山
(本文内容由公众号“千猴马的游戏设计之道”提供,转载请征得同意。文章仅为作者观点,不代表GWB立场)
在今天,这些问题的解决方案网上有一大堆,不同的人用不同的方法去解决了一些问题,你可能随便一找就有各种思路、各种代码可以看,非常方便。带着这个问题你去寻找知识,这本来就是一个非常简单的事情,百度、谷歌一打开一搜索就有不少结果。但是请注意,到这里只是一个开始!如果你觉得网上随便找点就能用了,甚至问题解决了,就大错特错了!为什么呢?因为每个人都是在不同的条件下用不同的方法“解决”这个问题,这里的“解决”之所以打个引号,是因为并不是每个人都真的解决了这个问题,尤其是在今天,你看到的大多视频和帖子,“教”会你的并不是真的去解决一个问题,而是凑了个效果,他们用的手法只是做了一段视频甚至一个编辑器,增加了对外行的说服力(可信度),但是很多方法,仅仅只是在他们的“环境”下有效的,这个“环境”指的是他们需要做的东西为主的一个条件——既然他们能运行起来,就必然是有一定有用的东西,这些有用的东西是有启发的,但是他在你的环境下未必正确。我们以“二段跳”举例,比如有人教你二段跳加一个计数,每跳一下+1,这样当你的计数大于n(n=2)的时候就不允许再跳了,这样做对不对?在这个“环境”(也就是啥也没有的环境)下,当然是没有问题的,别说2段跳,你要n段跳这样行不行?当然看着没问题。这就是知识——它在一定环境下,是一定对的。但是问题来了,你的“环境”和他说的一样吗?这就要靠分析问题了,分析出你的环境是什么。粗暴地说就是“先把舌头捋直了,把话说清楚”,为什么这么说呢?因为我们通常都喜欢用概括性的语句说一个问题,概括度越高就越没有问题,比如这个“二段跳”就是一个概括,因为它概括了所有的跳跃中可以再跳跃的情况,但是,每个游戏的二段跳都一样吗?为什么会不一样?这些游戏的二段跳有什么区别?
剑网3的二段跳,是只要你的状态(状态机的状态)是空中,并且第二次跳跃为false,就可以再跳一次。这个很好理解,也就是刚才我们说的,做一个计数器n的话,你要n段跳都能实现对吧,但是剑网3的环境,明显就是远不如恶魔城和艾尔登法环复杂的,所以这样做是没问题的。恶魔城的二段跳,恶魔城的二段跳从玩家的角度,如果欠缺思考的去理解的话,和剑网三没区别,就是“你跳起来落地之前可以再跳一次”,真是这样吗?其实不是的,因为在恶魔城中有一个剑网三不存在的情况——我在空中挨打会进入受击动作,如果高度足够,受击动作先播放完了但是还没落地,角色要回归到下落动作,但是在这个下落动作中是不允许再次起跳的,那你用计数器和“空中状态”还能做到吗?是完全不行的。而相对恶魔城来说,更加复杂的是艾尔登法环的二段跳(法环里面走路是不能二段跳的,但是骑马可以),因为法环里面有跌落掉血和直接摔死。细心的玩家可能会发现,在法环里面,如果你悬崖边骑马跳跃跳出悬崖到落下一定高度再按跳是不会进入二段跳的。你的二段跳要的是什么?
所以你不能单纯的用一个概括词去分析这个问题,你说你要个“二段跳”,那么请问几个细节:1、空中受击会不会改变动作,改变之后是不是依然允许二段跳?比如我先跳起来,然后挨打了,这时候我使用受身动作恢复了下落动作,能不能再跳?或者受身动作本身记在“二段跳”里面?这实际上都是对的做法,关键看你的游戏要怎么样的设计。2、跳起来什么情况下允许二段跳?比如我跳起来先做了一次普通攻击,允不允许二段跳,那如果我跳起来只是一个很快捷的动作比如丢了个飞镖,允不允许接着二段跳?这是一个风格问题,需求明确了都能实现,问题是需求是什么呢?是跳起来之后做了别的动作就都不能二段跳了,还是有些动作之后不能二段跳了,还是所有动作之后都还可以二段跳?3、游戏中存在摔死吗?这里“摔死”概括2个情况,其一是马里奥的摔死,就是“摔出地图”了会不会死,这个我相信绝大多数是会死的,至少你被比如UE这种引擎Kill Z了,总得死了吧,不然角色都没了是吧,打个补丁也得让他死了;另一个情况是法环、盐与避难所之类魂系以及wow之类,这种标准的即时回合制游戏的设定——从很高的地方掉下来会掉血(法环是分段掉血,wow是按高度提高掉血量),因为会掉血,所以肯定会摔死(法环是到达一定高度就一定摔死,这和wow又不一样了)。那么请问,在这个设定之下,二段跳能救命吗?比如剑网3里面(至少我玩的版本,我是到70级开放后2周弃坑的),角色快落地的时候二段跳就没事儿了,不管之前是不是会摔死。
所以请先定义“二段跳”
这样的细节问题不仅如此,上面只是典型的问题,随着你的游戏设定,可能还会浮出更多更多问题,那么请问——你要的二段跳究竟是如何?(你不用回答我,告诉自己就好了)就比如你原本想的是“只要跳起来以后再按一次跳就是二段跳”,现在多了一环“悬崖边走下去的而不是跳下去的算是跳吗?不算是不是走下去就不能二段跳?”这时候你就会想“那只要在空中就可以……”然后进一步考虑“空中受击的时候能不能二段跳?”于是就有了“空中什么条件下可以二段跳?”如此下去需要深入思考的细节非常多,不同的细节决定了不同的做法。而是否会摔死,还会在另一个维度给你二段跳增加“麻烦”。当你分析清楚之后,你再看看你网上搜索的那些东西,还能帮你实现需求吗?至少直接实现是未必的,但并不是一无是处。这时候你就需要进一步动脑筋研究你到底要做什么。与其说这是一个再学习过程,不如说这才是真正的需要动脑筋需要智慧的点。正如上面说的,不同风格的二段跳实现的方式是不同的。我们回到上面说的3个例子:允许“计数器做法”的环境
首先是剑网3式的,也包括wow这种游戏,在这种游戏里面,假如我们做了二段跳,有什么道理“在空中不能二段跳”吗?是没有的,因为他们是更接近于回合制游戏的即时回合制游戏(即时回合制游戏的一个风格),所以受击动作只是假象,并不影响逻辑,没有什么实际效果,换而言之比如你在攻击动作中挨打,这并不会影响你的攻击,你还是管你攻击,只是因为要做攻击动作所以不做优先级更低的受击动作了,攻击依然有效了。同理跳跃也是如此,因为“挨打”这件事情在这类游戏中,无非就是一个“掉血”的事情,完全不影响其他任何内容,所以的几段跳都不会受影响,同理的推理一下其他动作,也是如此。只有一个例外,就是角色死亡了。那我们来归纳一下,就是——只要没有别的因素会干扰跳跃,那么就可以无脑用“计数器做法”来做二段跳。符合这样条件的,当然还有绝大多数的FPS和TPS,尽管你可以跳着开枪,但是开枪不会影响你的跳跃,即便是击退等因子,对于跳跃也没有本质的影响,可以用状态机(FSM)管理逻辑数据的游戏,都可以这么做。UE提供的角色移动框架就是这样的——你让角色jump(一个状态),他就有个计数器管理n段跳,除了jump状态之外,是没办法二段跳的(除非用各种失控的方法去打补丁),所以UE的二段跳仅仅适合于射击游戏和“更MMORPG的即时回合制游戏”(比如你要做一个TPS的Diablo,很多国产“动作游戏”都是这样的),他的局限性是无比之高的!动作游戏的做法
既然我们用的是恶魔城等例子说到“计数器做法”,那么我们就深入看看动作游戏该怎么做二段跳。动作游戏其实是不能用状态机来做的,因为状态机只能是有限状态机(FSM),不存在“无限状态机”,所以状态机的状态必须在任何自然环境下都可以枚举的(switch case的值必须可以做成枚举),动作游戏的动作是不胜枚举的,所以没法用有限状态机。在动作游戏中,动作之间的“连续”是由Cancel来决定的,如果概括的来说,就是“当前帧在什么条件下可以被切换为哪个帧”,其中Cancel是一个“关键条件”,而“二段跳”这个问题也是如此。首先你必须理解动作和画面的区别,“动作”是一个逻辑数据,一个角色同一个时间只可能处于一个动作(确切地说是处于一个动作帧,动作是一个归纳性逻辑,是允许出现在代码里让人coding更方便的),这里的“动作”指的是他的逻辑数据,而这个逻辑数据中包含了一个信息就是视觉的“贴图”用的是哪一个,简而言之,你可以理解为动作A和动作B是不同的动作(这是废话),但是动作A指向的“贴图信息”(就是玩家看到的画面,你可以理解为一个动画、一个动画帧等等)和动画B指向的“贴图信息”可以是相等的值,就像攻击力A可以==攻击力B一样的道理,所以即使是看起来完全一样的动画,他们可能也是完全不同的动作。了解了上述基础之后,你应该明白一个道理,有二段跳的动作游戏里面,第一段跳就是这个“动作A”,第二段跳就是这个“动作B”,动作A的过程中大多帧都可以被动作B直接Cancel,这就形成了二段跳的现象。也因此如果在空中受击了(做出了受击动作),这个受击动作显然就是“动作C”了,C和AB没有关系,所以自然就不能做出二段跳了,除非配置C的过程中某些帧可以被A或者B的Cancel。所以接下来一个问题“受身动作中是否还能二段跳”的答案就很清晰了——受身动作(设为“动作D”)中是否允许被B的Cancel,如果允许,那么就是可以,不允许就不可以,如果可以被A的动作帧Cancel,甚至会形成3段跳或者更多段。而如果被B的Cancel成立,那么演算一下,空中依然是可以无限段跳的——跳起来被打→受身(D)→二段跳(B)→挨打→受身(D)→二段跳(B)……无限循环的可能性是存在的。老头环又是怎么做的呢?
实际上老头环的跳跃框架更接近于UE的Montage系统,这个Montage是什么,你可以通过知识(我们上面说的“知识”也就是上网搜)学习到。用UE4的动画核心机制之一的Montage来做法环式跳跃可能就是这样吧老头环把一个完整的跳跃动作和一个完整的二段跳动作做了2个Montage,里面分了多个Section,这些Section包括:Start:开始起跳阶段,二段跳一定会进入这个阶段,但是一段跳未必,因为你可以从悬崖上走下去。Rise:跳起来升空阶段,一段跳中,在达到跳跃最高点的时候自动切跳到Fall1,也是因为有悬崖边走下去的时候,所以未必会走过这个Section。Fall1:下落1阶段过程,这个阶段中有一个AnimNotifyState专门管理落地处理(我们称之为HitGroundCheck),一旦落地,立即跳转到OnGround1,这个阶段还有一个AnimNotifyState管理,允许玩家使用二段跳动作来Cancel这个动作(仿动作游戏做法)。二段跳的Fall1时间长度是明显短于一段跳的。OnGround1:顺利落地,正常的跳跃到这里就结束了,所以这个Section是没有Next的。Fall2:动作和Fall1一样。如果Fall1的HitGroundCheck没有工作,顺利走完了Fall1就会进入Fall2,所以Fall1的后续Section是Fall2,OnGround1\OnGround2都是单独的Section。在这个Fall2中,也有一个HitGroundCheck,但是是切换到OnGround2的。Fall2开始是不接受二段跳的,所以不存在另外一个AnimNotifyState。OnGround2:和OnGround1用的一样的动画片段,但是不同的是其中有一个AnimNotify,这个Notify的作用是扣血。Fall3:如果Fall2走完,就会自然进入Fall3的Section,Fall3和Fall2类似,只是HitGroundCheck走向OnGround3。OnGround3:摔死动作,不管你多少血,到这里就得摔死。FallDead:Fall3自然走完进入,这里有一个AnimNotify,告诉游戏角色死亡,如果角色有PlayerController,就播放死亡的镜头。正是因为这样的实现,老头环才能做到不同高度阶段不同的掉血,而lua脚本中的LandDeath只是一个辅助检查,是在落地掉血的函数中进行判断的,所以即便是Fall1落地,因为高度问题依然会死亡,但是问题是LandDeath中的“高度”是起跳时和落地时的,所以用了以后二段跳讲道理是不会摔死的(有人要说了,我能不能在第一次跳跃的时候就记录作为起跳高度呢?可以啊,那么请问,这个起跳高度什么时候清空?在游戏开发中,很多时候我们用类似这样的逻辑看似解决了问题,但是很多时候,这样的变量只有“开始”,很难“结束”,当然这是另一个技术问题)。那你的解决方案是什么?
说到这里,问题回来了,你想用的解决方案是什么呢?还是的,我上面告诉你的3个方法,都是在3个不同环境下的,这些环境不一定适合你,但是也并不是对你一无是处的,你可以参考,然后思考自己的环境下,采用什么策略,最后还是得靠自己根据实际问题去想出解决方案的,别人的知识,顶多只是解决一些策略细节的。在你根据分析,得知环境之后,你运用了知识和智慧,“解决了”这个问题了。是的,他工作了,但是他真的是最好的解决方案吗?未必是,当然也不是马上就要去寻找更好的方案的。你应该记住他——记住这个环境,记住你的做法和抉择,记住你的智慧(选择方案的理由),在今后的生活和实践中,多去思考,每当你学到新的东西或者有新的想法的时候,尤其是接近的想法,请回头想一下,你现在的解决方案还有什么可以优化的空间。这个过程就叫做总结经验。当你经过了足够多的项目经验了(当然这个“足够”只是相对过去的自己的),你会彻底改观自己曾经的做法,要勇于推翻,建立新的知识(方法),然后分享。这才是这个过程中最有价值的一环。所以,想实现一个功能玩法的时候该如何?
就是不要觉得自己不会,在需求(或者通篇说的“环境”)明确之前没有人会,明确之后也未必马上就会。还是要开动脑筋,结合知识和经验去分析怎么面对。游戏开发最有趣的地方,就是每个游戏的“环境”都不同,很难总结出通用的来。