距离匹配
在使用距离匹配时需要先在插件中开启AnimationLocomotionLibrary和AnimationWarping这两个插件
基本概念
游戏中动画驱动有两种方式,分别为位移驱动和动画驱动。位移驱动中玩家控制角色胶囊体的运动,动画自己播放,这种方式会导致角色动画的步幅与移动速度不匹配;动画驱动是由动画的根运动来驱动角色位移,这种方式可以很好的解决角色运动中的滑步现象。
基本原理
假如我们有一个起步动画,我们将角色的位移提取为距离曲线,同时每一帧获取曲线上的值,这个值就是角色的位移距离(距离起点的距离),将该值应用到角色的位移中就可以实现步幅匹配。
提取距离曲线

提取距离曲线主要使用DistanceCurveModifier类,这个类主要包含的内容如下:
1 | enum class EDistanceCurve_Axis : uint8 |
我们来逐个解析各个参数的含义:
- SampleRate:采样频率,即每秒采样多少次,默认为30次,采样频率越高,曲线值与实际位置的误差越小
- CurveName:采样的曲线名称,默认为Distance,供外部获取曲线值
- StopSpeedThreshold:速度阈值,用于计算动画序列的最小速度
- Axis:采样轴,即采样哪几个轴的位移,默认为XY,即采样X和Y轴的位移(水平位移)
- bStopAtEnd:是否选择在动画结束的时间作为速度的最低时间
- OnApply_Implementation:实际进行采样的函数,实现具体的采样逻辑
实现代码如下:
1 | void UDistanceCurveModifier::OnApply_Implementation(UAnimSequence* Animation) |
对源码进行分析:
- 这一步判断动画是否合法以及是否开启骨骼根运动
- 添加一条非元数据曲线,并声明需要使用的变量
- 寻找最低速度:
1 | // 判断是否直接使用动画结束时间作为最小速度 |
- 实际生成采样曲线
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// 计算采样间隔,由暴露给蓝图的值决定
SampleInterval = 1.f / SampleRate;
// 计算采样次数
NumSteps = FMath::CeilToInt(AnimLength / SampleInterval);
float Time = 0.0f;
// 遍历采样
for (int32 Step = 0; Step <= NumSteps && Time < AnimLength; ++Step)
{
// 防止采样超出动画时长
Time = FMath::Min(Step * SampleInterval, AnimLength);
// 用来判断是起步还是停步
// 如果是起步动画,速度从0开始递增,速度最小值一定为正数且是开始的时候,所以TimeOfMinSpeed一定比Time小,得到的为1.0f
// 如果是停步动画,速度逐渐递减到0,速度最小值一定为负数且在动画最后达到最小,则TimeOfMinSpeed的时间一定比Time大,得到的为-1.0f
const float ValueSign = (Time < TimeOfMinSpeed) ? -1.0f : 1.0f;
// 提取从TimeOfMinSpeed到Time之间的根运动距离
const FVector RootMotionTranslation = Animation->ExtractRootMotionFromRange(TimeOfMinSpeed, Time).GetTranslation();
// 将值添加到曲线中
UAnimationBlueprintLibrary::AddFloatCurveKey(Animation, CurveName, Time, ValueSign * CalculateMagnitude(RootMotionTranslation, Axis));
}
通过提取的距离曲线,我们可以实现起步与停步的步幅匹配
起步匹配

起步动画主要依靠AdvanceTimeByDistanceMatching,通过序列求值器选择每一帧的动画进行播放
函数声明
1 |
|
函数解释:根据动画前进的距离来设置动画的前进而非使用时间,这需要一个用于描述动画根骨骼位置的距离曲线,这个曲线我们可以从UDistanceCurveModifier中的来获取,这个在之前已经解释。
主要的三个参数为:
SequenceEvaluator:当前动画的序列求值器
DistanceTraveled:本帧移动的距离
DistanceCurveName:距离曲线
函数实现
1 | FSequenceEvaluatorReference UAnimDistanceMatchingLibrary::AdvanceTimeByDistanceMatching(const FAnimUpdateContext& UpdateContext, const FSequenceEvaluatorReference& SequenceEvaluator, |
停步匹配

当角色停止运动时(玩家不再有运动方向的输入),此时角色会逐渐减速,这时需要计算角色的运动距离,然后将这个距离与动画进行匹配
GetPredictedStopDistance:这个函数已经提供了用于预测角色停止运动后的前进距离,在C++中为PredictGroundMovementStopLocation
DistanceMatchToTarget:这个函数用于将预测的距离与动画进行匹配
GetPredictedStopDistance
定义
1 | /** |
可以看到注释内容为:通过角色移动组件中的属性来预测当角色停止运动时角色移动的位置
- Velocity:角色的速度
- bUseSeparateBrakingFriction:是否使用单独的制动摩擦力
- BrakingFriction:制动摩擦力
- GroundFriction:地面摩擦力
- BrakingFrictionFactor:制动摩擦力因数
- BrakingDecelerationWalking:制动减速度
实现
1 | FVector UAnimCharacterMovementLibrary::PredictGroundMovementStopLocation(const FVector& Velocity, |
DistanceMatchToTarget
定义:
1 | /** |
注释为:通过距离来设置序列求值器的播放时间,通过每帧选择动画中与角色剩余距离匹配的点来实现
- SequenceEvaluator:序列求值器
- DistanceToTarget:目标距离,即预测的行进距离
- DistanceCurveName:距离曲线
实现:
1 | FSequenceEvaluatorReference UAnimDistanceMatchingLibrary::DistanceMatchToTarget(const FSequenceEvaluatorReference& SequenceEvaluator, |
流程图
1 | flowchart TD |
注意事项
- 使用UE版本为5.5.4
- 确保动画已开启根运动
- 距离曲线名称需与代码中一致
- 采样率过高可能导致性能问题
- 本文作者: KongXinQing
- 本文链接: https://13114987559.github.io/2025/11/30/essay/距离匹配/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!