3D动作类游戏操控系统简述
刷Feed的时候看到有人翻出一个一年多以前的问题,问动作游戏都要在动作上编辑哪些参数,发觉自己已经比当初看到问题时多了很多可以说的东西,就准备了一篇回答,最开始是单纯为了整理帧事件的,然而发现不涉及到跳转信息之类的没法说明,于是越说越超纲,最后还是决定单独发了文章。因为还有开发任务,没法说到很细致。
这篇文章的主要关注点还是在Controller系统的整体结构,并不针对特定游戏,所以格斗游戏,狭义的动作游戏和ARPG可能都需要跑完这套系统,只是根据游戏类型在系统的特定部分拓展和配置。为了方便,很多东西都只是简单列下来,因为不同游戏的具体要求差别会很大,就不细说了。
希望对有兴趣的玩家和开发者有所帮助。
下面直入主题。
一般游戏的处理逻辑都可以简单拆成3个部分(参见Steve Swink - Game Feel, 2008)
接受输入
将输入翻译成游戏逻辑
执行游戏逻辑
当然也有更细致的划分方式,不过我主要还是从这3方面往下展开说。
1.接受输入
1.1. 输入设备与按键映射
键盘
鼠标
手柄
1.2. 单一操作
简单按键:信号为0/1
按下:按下按钮
点击:按下在一定时间内松开
长按:按下达到一定时间
蓄力:按下达到一定时间并松开
Trigger类按键:信号为0/1和一个0到1的浮点数,一般动作游戏不用那个浮点数
摇杆类:信号为一对0到1的数组
正方向吸附:当摇杆角度接近正前/后/左/右方向,误差在一定值以内时,默认处理为前/后/左/右方向。
似乎不同的手柄在硬件端就对这类信号有所处理,此处略过不提。
1.3. 复合操作
组合键
同时按下:某一个时刻两个键同时处于按下状态
精确同时按下:两个键的按下事件前后间隔不超过一定时间
拖动:鼠标与触屏的特有操作组合
按下 -> 指针移动 -> 松开
指令序列:主要用于编辑指令技表(不依赖动画序列的技表,如双击,236A,↑↑B)
指令序列时间轴 / 其他数据结构
每当完成一次有效输入后,向前一定时间回溯有效操作的序列,如果满足条件则生效。
比较典型的是如春丽28K这样的指令技,可以在角色没有动作响应时提前按下2积累时间,可以据此判断指令是在输入阶段即生效的,不依赖游戏逻辑和动画。
2. 将玩家输入翻译成游戏逻辑
主要通过命令管理器Command Manager或者类似功能的模块来实现,玩家输入的指令被转化成命令,通过命令之间的关系控制输入过滤、按键缓存(Input Buffering)、打断与序列技表(依赖动画序列的技表,如AABBA)
2.1. 命令
输入响应:一般而言命令和玩家输入是一一对应的,如X对应轻攻击,Y对应重攻击
命令优先级:不同命令之间的相互打断的逻辑,高级命令可以随时打断低级命令
命令缓存白名单:每一个命令能够缓存其他哪些命令,下面会细说
消耗检查:依赖动画上的消耗信息,如果当前资源存量不足则不会执行
驱动动画:命令到动画的映射关系。
当角色武器不同时,轻攻击指令会驱动不同的动画,需要命令管理器能够处理武器 -> 动画的映射关系,可能有一个武器Movelist需要维护,超纲不再细说。
2.2. 按键/命令缓存
一般序列技表的游戏都会使用,为了减少玩家输入精度的辅助措施,在上一个动作执行中按下下一个动作的指令,系统会记住该指令,到能执行的时候执行。
缓存时长这个值比较微妙,短了玩家感受不到,长了又会导致不受控制,目前的经验是最早跳转前0.2s为宜,具体情况视动画而定。
格斗游戏不允许缓存所以有目押的严苛玩法,而魂系列经常因为按键缓存时间长而遭受诟病。
一般原则是高级命令缓存覆盖低级命令缓存,同等级命令新命令缓存覆盖旧命令缓存。
2.3. 命令/动画跳转时间轴
对接命令控制器,用于动画的跳转的驱动。因为担心不够精确,这里没有使用广大意义上前摇/后摇/取消的概念,而是这样的一个标准时间轴。
动画开始 -> 缓存保护 -> 提前取消 -> 最早退出 -> 最迟退出 -> 命令重置 -> 动画结束。
动画开始:没什么好说
缓存保护:在命令/对应动画执行中,在动画开始 -> 缓存保护时间段,同样的命令不缓存,以免玩家快速连续点击的时候马上又缓存了一个命令,会多执行一次,造成不受控制的感觉。
提前取消:一些比较轻的攻击,玩家的期待是在前摇阶段可以被闪避等动作取消,Moba游戏攻击/技能前摇靠移动/停止指令取消,可以用来骗招,动画开始 -> 提前取消的时间轴标记了这一段时间。
最早退出:当动画播放到最早退出时间,可以开始跳转到已经缓存了的新动。画。
1)在缓存保护->最早退出时间段,玩家的输入命令可以缓存。
2)缓存保护->最早退出时间段,原则上可以晚于动画结束时间,以创造类似“内置冷却”的效果。
最迟退出:同样用来标记一段辅助输入的时间,在最早退出-> 最迟退出的时间追加指令,连技不会中断。
命令重置:标记连技中断的时间,一般此时动画会开始向待机动作跳转。
命令重置 -> 动作结束阶段,输入命令,则连技中断。如果连技X->X对应动画A->B, 在X命令重置后才追加X指令,只能触发A->A。
最迟退出 -> 命令重置时间段,可以不处理,也可以开启另外一个缓存,在命令重置时间点后执行重置过的连技。
最迟退出 -> 命令重置时间段也可以做成特殊跳转,实现A ? A这样的等待攻击,在序列技表中也比较常见。
如果一节等待不够还可以加多节,常见于蓄力到不同阶段退出的指令技。
命令重置时间原则上可以位于动画结束之后,可以实现多段翻滚的内置计数,攻击之后移动一段时间再攻击可以接上之前的连击这样的效果。
细则补充
任意两个命令之间的跳转不必要有上面的全部信息。
轻攻击->移动一般只需要有最早退出时间一条即可正常工作(因为移动是一个如果不生效玩家就会持续输入的指令)
轻攻击->翻滚只需要提前取消和最早退出两条。
只有在涉及到比较复杂的序列指令时才会有复杂的配置,例如同时出现 A->A,A ? ->A,A -> A(长按),这类技表一般设计的时候就会避免。
命令控制器需要能够处理一些命令Overlap时候的判断。
当动画A处于到动画B的跳转过程中,这时候的新指令是响应A的跳转时间轴还是B的跳转时间轴?
当上一个命令的跳转时间轴超出动画本身之后,新的有效输入是用当前动画的时间轴,还是上一个(已经播放完的)动画的时间轴?
命令控制器的必要性视具体游戏类型而定,如果没有复杂的指令表的话,大可以不必做,全部与输入逻辑一并处理。
很多其他东西也有更直接/顺畅的实现逻辑,具体项目具体分析,不要为了秀操作强行cram一堆不合适的东西。
上述的跳转时间轴本质上揉起来了两部分内容,一部分判断输入的有效/无效,一部分判断动画的执行时间,原则上是可以将两部分抽象出来分别配置的,这样做肯定更精确,只是需要的维护量也更大。
上述只是Base层的命令控制,实际上一个命令驱动的动画可能不仅是Base层,还会有若干层的Additive Layer,例如起跑/停止时的强调动画,武器的协同动画(鞭子之类的),边走边播的动画,手势与表情动画等。
命令控制器足够优秀的话,完全也可以给AI使用,做Replay之类的也方便。
3. 执行游戏逻辑
终于到大家比较在意的动画阶段了?输出经过处理变成命令,最终可以用于驱动游戏逻辑,主要是播放角色动画,根据动画时间轴执行帧事件,调用对应的游戏逻辑。
动画上主要是帧事件信息和打击信息两类,简要整理如下:
3.1. 帧事件信息
动画播放到什么阶段要发生什么事情。
距离吸附:在目标位于一个有效范围内时,玩家会滑行一小段距离以保证能够命中,依赖目标获取的逻辑。
有效范围
位移速度
持续时长
曲线(可选)
转向吸附:在目标位于一个有效范围内时,玩家会自动转向目标以保证能够命中,依赖目标获取的逻辑。
有效范围
转向角速度
持续时长
曲线(可选)
武器开关
有一些游戏会在玩家攻击的时候显示/隐藏武器,很不幸我在做的游戏就是这么麻烦,不过也省去了制作不同武器的Idle pose的问题。
攻击碰撞盒开关
开关角色 / 武器身上的碰撞盒来识别是否命中
发射子弹
关联到子弹
子弹比较复杂,简要列举
弹道信息 - 直线,抛物线,追踪,回力标等,具体每一种弹道有相关的细节参数
碰撞信息 - Hit次数,穿透,闪烁相关的信息
特殊行为 - 创建其他子弹、AOE、Dummy、Buff等
伤害信息 - 与动作打击信息大体一致
添加Buff
每个Buff有具体的逻辑,不详细说了
消耗:玩家的动作在此事件前被打断,不会消耗资源。
消耗资源
消耗值
特效:分为多类
拖尾开关:原本对象绑定在武器上,开启即可跟着武器画出轨迹。
武器动画:一些拥有变形的武器动画,本质逻辑和特效一样,也可以不当成特效另外做。
特效动画开关。
创建位置
打断回收,有一些特效,如果攻击动作被中断则希望也能够将特效一并中断。
音效
动作自带的音效播放,一般帧事件只负责时机,具体表现由音效师在声音引擎里维护,略。
动画速度:在特定时间减慢/加快动画的播放速度,以改善表现。
目标速度
多少时间内变化到目标速度
游戏速度:在特定时间减慢/加快整个游戏运行的速度,以改善表现。
参数同上
受击保护(霸体)开关:动作是否会被普通受击动作打断。
时长
无敌开关:翻滚等会有无敌帧的动作
时长
破招开关:用于盾反/招架等机制
时长
碰撞盒:破招的碰撞盒与当前武器的碰撞盒很可能不会一致,需要另外配置。
伤害惩罚开关:用于实现格斗游戏Counter效果,黑魂的翻滚伤害惩罚等。
时长
承受伤害系数
相机演出:一些攻击可能没有命中也有强烈的效果。
震屏,后面命中表现会具体一点说一下
特写演出
3.2. 打击信息
主要用于伤害结算,不同的游戏有不同的结算流程,这里只说一些通用的吧。
伤害相关
伤害系数:动作的造成的伤害倍率,一般以乘法算在伤害公式里结算。
MH大剑蓄力斩需要更复杂的结构。
削韧/气力:一般为了控制动作的节奏都会一个不同于HP的值来控制动画的节奏,实现例如韧性霸体(黑魂) / 气绝(仁王、街霸)之类的效果。
异常积累:结构上和上一项基本一样,主要是类似MH毒/眠/麻/晕/爆,黑魂冰/毒/血/咒,这种特殊效果,结算方式要不要带动作系数一起因游戏而异。
攻击类型:用于攻防检查决定伤害倍率。
提供给引擎/声音引擎,决定播放怎样的Hit特效与音效。
附加Buff
不同的Buff会在伤害流程的不同阶段生效,具体视Buff效果与伤害结算流程而定,下面简单举例:
命中阶段,例如连续命中加伤害。
伤害结算阶段,例如对特定护甲类型加伤害。
After hit阶段,例如吸收造成伤害一定百分比的血量。
命中表现相关
帧冻结
时间
速率
曲线
衰减:用于控制连续命中多个目标不发生多次冻结,视需求配置。
相机运动
手K相机动画:能够稳定地控制相机的State,但是处理叠加的时候会比较困难,极端情况下震动1+震动2可能变成静止,所以一般震动会强切(毕竟相机最好只播一个动画。
算法模拟
运动方式:PedX/PedY/Dolly/Pitch/Yaw/Roll
运动强度:强度 / 频率 / 扰动
可以使用统一的Intensity和衰减率来控制,便于叠加,只是优秀的扰动算法参数很多并不好维护。
受击方表现相关
攻击方向:用于结合角色站位判断受击方播放怎样的受击动画以匹配攻击方向。
受击Code:用于决定攻击命中之后驱动怎样的受击动画。
小受击:局部Additive Pose,不打断当前动作。
普通受击:打断当前动作,但是霸体/受击保护可以免疫。
受击 / 击退 / 击倒 / 击飞
其他受击:有特殊逻辑的受击表现,简要列举。
演出:投技、盾反、背刺、斩杀等,涉及到动画协同播放,相机演出和游戏逻辑的变化(比如AI停止攻击)
异常受击:异常伤害积累到特定值时触发,眩晕/麻痹等。
浮空相关
没做过,一些游戏机制允许无限连只是要根据浮空阶段受到的伤害动态控制下落速度,感觉也会很复杂。
4. 总结
以上帧事件、信息等具体内容列举并不固定,可以任意添加/精简。
所有关于两个连续变量的映射关系(最常见是某一个值如何随时间变化)最终都可以转化为手K的曲线,或者也可以使用各种Easing算法来实现平滑处理,具体看项目需要配置到多细致。
很多事件需要的信息也大可以不必配置在动作上,可以来源于角色固有参数,系统固有参数,装备/饰品的对应参数等等。总结起来就是,每实现一个特定的效果都有无法回避的系统复杂度,需要足够的信息才可以生效, 信息记录在哪里,系统怎么拿到这些信息,哪些信息定死哪些信息开放出来配置,视具体项目要求的精细度,以及工作人员擅长的配置方式而定。
Controller一般来说是大型游戏3C里面最复杂的一项(Character和Camera都相对简单一些),需要和大量系统的协同工作才能生效。维护一套动作控制系统并不难,并不需要多少天才奇想,需要的更多的是耐心和细致,以及多方开发人员的密切配合。
最后说一句,国内还是有做动作游戏的开发组的,虽然水平未必好,但是总归是有的。