UE4 Advanced Locomotion System V3插件 角色的控制分析,关键动画逻辑分析
Advanced Locomotion System V3是一个主角动作“真实感”很强的一个工程,需要学习借鉴。
本文对UE4的一个动作demo的主体结构分析,以及对我们关注的关键动画逻辑的分析
https://www.unrealengine.com/marketplace/advanced-locomotion-system-v1
1 Advanced Locomotion System V3主体结构分析
本文重点关注的是角色的控制和动作,所以会跳过无关的模块。
1.1 player基类关系分析
分析方法:
在“世界大纲视图”,搜到MannequinCharacter_Player,点击右侧的<编辑MannequinCharacter>,会弹出来一个类默认值窗口,点击上方蓝色的“打开完整的蓝图编辑器”,即可查看当前类的蓝图,点击工具栏的“类设置”,在细节窗口可以更改此类的父类,查看此类继承的接口。在当前类的蓝图的右上角,可以查看父类,此例中,MannequinCharacter的父类为ALS Base Character;使用类似的方法,可以看到ALS Base Character的父类是Character,至于Character的父类就需要查看unreal的文档或unreal源码了。
结果:
MannequinCharacter_Player是MannequinCharacter类的一个实例,MannequinCharacter类继承关系如下:
ALS Base Character => Character / ACharacter => Pawn / APawn => Actor / AActor => Object / UObject => UObjectBaseUtility => UObjectBase
值得注意的是除了主线继承以外,有些父类继承的接口:
ALS Base Character => ALS Interface
APawn => INavAgentInterface
MannequinCharacter类几乎是一个空类,所以下文不再提及;Character及其以上的类为引擎内置类,不是本文的关注点。所以接下来重点分析ALS Base Character 类 和 ALS Interface 接口
1.2 class ALS Base Character
class ALS Base Character 主要实现了:
- 控制角色的rotation,见Manage Character Rotation(tick) 、 Interface Events
- 实现角色的多种运动方式的相互切换(ALS_MovementMode ALS_Stance ALS_Gait), 速度的控制,见Do Every Frame(tick) 、 ALS Events、Default Character Events
- 角色的初始化逻辑,见Begin Play
- Player Input的处理,例如各种键盘、鼠标事件,见PlayerInputGraph
- 相机系统, 见Camara System
- 布娃娃系统, 见Ragdoll System
- 网络系统,服务端相关的逻辑, 见Networked Events
结合本文的主题,接下来之重点介绍前2项,3-7接跳过。
1.3 角色rotation的控制
函数SetCharacterRotation
控制角色的rotation的核心代码在函数SetCharacterRotation(TargetRotation, InterpRotation, InterpSpeed)
参数:TargetRotation rotation 目标旋转; InterpRotation bool 是否插值;InterpSpeed float 插值速度
SetCharacterRotation 最终会调用引擎的SetActorRotation(NewRotation)来实现旋转。
Jump状态、IsMoving状态,都是直接调用的SetCharacterRotation,不再赘述,下面介绍IsMoving为False的情况。
Not IsMoving时的角色转向(TurnInPlace)
基本原理:在播放TurnInPlace旋转动画的时候,根据动画设定的轨迹,每帧对角色增加一个旋转增量。
TurnInPlace对角色执行旋转的代码在:Interface Events => AddCharacterRotation_BPI
可以看到, AddCharacterRotation_BPI主要执行了函数AddCharacterRotation(rotation addAmount),addAmount是一个旋转的增量,是给当前角色rotation加上addAmount。
AddCharacterRotation_BPI是在播放TurnInPlace相关动画的时候,逐帧触发的:具体见以ALS_N_Turn_L为前缀的骨骼动画,里面有一个名为TurnInPlace_AnimNotityState的AnimNotityState,TurnInPlace_AnimNotityState中保存的有驱动Character的旋转轨迹。
具体播放动画的逻辑在:Mannequin_AnimBP蓝图
首先是用Montage对ALS_N_Turn_L为前缀的骨骼动画封装;然后在Mannequin_AnimBP蓝图中新建Montage变量(以N_Turn为前缀的变量),用以保存动画的索引。
在函数TurnInPlace(Delay) 和 TurnInPlace(Responsive)中,都会调用Montage变量进行动画的播放,Delay是通过鼠标左键转动镜头的时候用到,Responsive是通过鼠标右键转动镜头的时候用到;区别就是前者会加一个0.5秒左右的延迟;后者是实时响应旋转的。TurnInPlace函数决定了具体播放哪一个Montage变量,以及播放速率;大体逻辑为:旋转方向在60~130之间播放转90度的动作,130~180播放转全身的动作。
TurnInPlace的调用位置:Mannequin_AnimBP > 事件图表 > Do Every Frame > While Grounded > Turn In Place
1.4 角色速度的控制
由于走蹲切换,疾跑慢走的切换都是键盘事件触发的,这块逻辑从PlayerInputGraph里顺藤摸瓜即可,不再赘述,重点介绍加速机制,因为Neox的角色控制器默认是没有加速这个机制的。
Unreal引擎速度控制代码分析
Unreal角色控制器的代码在:CharacterMovementComponent.cpp
速度控制的逻辑主要在函数:
CalcVelocity(float DeltaTime, float Friction, bool bFluid, float BrakingDeceleration)
这个函数的核心就是计算Velocity += Acceleration * DeltaTime,里面一堆if分支只是为了处理一些特殊情况。各个参数的含义:DeltaTime为帧时间,Friction是摩擦加速度,bFluid是否在流体中(游泳或者飞行会用到),BrakingDeceleration是刹车加速度。
TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
这个函数是CharacterMovementComponent的每帧逻辑的入口,在这里我们可以看到Acceleration的计算方法:
Acceleration = ScaleInputAcceleration(ConstrainInputAcceleration(InputVector));
所以,最核心的加速度计算就是ScaleInputAcceleration:
FVector UCharacterMovementComponent::ScaleInputAcceleration(const FVector& InputAcceleration) const
{
return GetMaxAcceleration() * InputAcceleration.GetClampedToMaxSize(1.0f);
}
GetMaxAcceleration获取的就是MaxAcceleration属性,是由脚本层设置的。
InputVector的设置方法最终也是脚本层调用函数:
- Pawn.AddMovementInput函数
- PawnMovementComponent.AddInputVector函数
蓝图层(脚本层)分析
根据引擎的分析结果,在脚本层搜索MaxAcceleration,AddMovementInput即可找到相关代码。
AddMovementInput本质上就是键盘或摇杆的方向输入,具体逻辑见:PlayerInputGraph => MovementInput => PlayerMovementInput => Normal Input
MaxAcceleration其实就是角色的最大加速度,脚本层主要有两块用到:
- Update ALS Character Movement Settings
- Do Every Frame => Do While Grounded => Custom Acceleration
第1个是在状态切换 或者 状态对应的速度发生改变的时候调用
第2个主要是在Standing状态下,且处于Running或Sprint状态下才会每帧执行;主要为了实现每帧根据玩家的旋转角来设置不同的加速度,旋转角度越大,加速度越小。Sprint和Running是共用一个基准加速度(Running Acceleration),然后乘上在CustomAcceleration函数里乘上不同的系数(MovementInput/VelocityDifference),MovementInput/VelocityDifference表示相对于上一帧的旋转角度,旋转角小于45度,则系数为1,加速度比较大;旋转角大于130度,则系数为0.2,加速度比较小。
3 关键动画分析
掌握了上文的unreal的使用技巧,读懂动画蓝图Mannequin_AnimBP的逻辑并不难。
本章还待完善,因为有需求单插进来了,所以先暂停,后续有时间再补充
3.1 Unreal的融合节点简介
https://www.cnblogs.com/xiaoyaoliu/articles/14501740.html
3.2 逐个动画简介
本节主要按照策划的要求,分析每个骨骼动画都用在了哪里。
站立姿势的Idle
ALS_N_Idle_Additive(呼吸动画,可以和正常走跑叠加),ALS_N_Idle_Pose(普通Idle)
ALS_N_Locomotion
走跑动画
ALS_N_Stop_LF 和 ALS_N_Stop_RF
高速状态下停下来的动作
ALS_LF_Pivot(极速转向的动作)
ALS_N_Lean_Grounded(走跑、蹲行状态下,角色前后左右的倾斜效果)
ALS_N_Idle_Additive_Pose(不倾)、ALS_N_Lean_F_Pose(前倾)、ALS_N_Lean_B_Pose(后倾)、ALS_N_Lean_L_Pose(左倾)、ALS_N_Lean_R_Pose(右倾)
ALS_N_Lean_InAir(下坠状态下,角色前后左右的倾斜效果)
ALS_N_InAir_Additive_Pose(不倾)、ALS_N_InAir_Lean_F_Pose(前倾)、ALS_N_InAir_Lean_B_Pose(后倾)、ALS_N_InAir_Lean_L_Pose(左倾)、ALS_N_InAir_Lean_R_Pose(右倾)
ALS_N_AO(各方向的look动画,用动画融合实现LookAt)
ALS_N_AO
| 左转180度 | 左转90度 | 正前方 | 右转90度 | 右转190 | |
| 向上看 | ALS_N_AO_LU180 | ALS_N_AO_LU90 | ALS_N_AO_FU | ALS_N_AO_RU90 | ALS_N_AO_RU180 |
| 平视 | ALS_N_AO_L180 | ALS_N_AO_L90 | ALS_N_AO_F | ALS_N_AO_R90 | ALS_N_AO_R180 |
| 向下看 | ALS_N_AO_LD180 | ALS_N_AO_LD90 | ALS_N_AO_FD | ALS_N_AO_RD90 | ALS_N_AO_RD180 |
ALS_N_Turn(正常姿势,静止状态下,跟随镜头的转身动作)
所有ALS_N_Turn_为前缀的动作
跳跃相关动作
ALS_Flail ALS_N_Additive_LandCompression ALS_N_FallLoop ALS_N_Jump ALS_N_Land
Ragdoll状态下站起的动作
ALS_C_GetUpFromBack(躺着站起) ALS_C_GetUpFromFront(趴着站起) ALS_Curl ALS_Flail(jump fall也会用到)
下蹲相关动作
暂时不做下蹲,所以简单列举一下。
ALS_N_to_C_Idle(站立到蹲下) ALS_C_Idle_Additive(呼吸) ALS_C_Idle_Pose(普通idle),其他ALS_C_开头的动作。
ALS_LF_Locomotion ALS_LF_Stop(瞄准状态下的走跑冲动画)
ALS_N_to_LF_Idle(从idle到瞄准的过渡),所有ALS_LF_为前缀的动作。
我们暂时不需要瞄准,所以日后再研究。
未来的工作
这个样例也包含了脚步ik、ragdoll的相关逻辑,将来有时间也可以分析下,应该也有可以值得借鉴的东西。
浙公网安备 33010602011771号