关于 ue-animation-system
面向 UE 5.8 项目的动画系统开发技能,汇集运行时动画 API 与动画插件的参考。内容包括动画实例、蒙太奇、通知、曲线、混合空间、状态机及动画层。
主要功能
- 01动画实例与工作线程代理
- 02蒙太奇播放及结束回调
- 03动画通知与通知状态
- 04曲线、混合空间和状态机
- 05链接动画图层与根运动
适用场景
- 01实现线程安全的动画更新
- 02播放蒙太奇并处理混合结束
- 03创建动画通知以触发游戏逻辑
- 04配置 locomotion 混合空间和状态机
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ quodsoler/ unreal-engine-skills --skill ue-animation-system安装后在 Claude Code 中输入/ue-animation-system确认已加载。
附带文件references/anim-notify-reference.mdreferences/locomotion-setup.md
详细介绍
UE 动画系统
目标引擎:UE 5.8。以下 API 已根据 5.8 头文件验证;旧版形式列于“已弃用 — 请勿使用”下。
涵盖 Engine 模块中的运行时动画路径 — UAnimInstance、FAnimInstanceProxy、UAnimMontage、UAnimNotify/UAnimNotifyState、曲线、混合空间、动画状态机、关联动画层和根运动 — 以及 5.8 随附的动画插件(PoseSearch、MotionWarping、Chooser、IKRig、ControlRig、BlendStack、OptimusCore、UAF)。Build.cs:Runtime/Engine/Classes/Animation 下所有内容使用 Engine,辅助动画节点(例如 FAnimNode_LayeredBoneBlend)使用 AnimGraphRuntime;下表逐行列出插件模块名称。
上下文
如果 .agents/ue-project-context.md 存在,请阅读它(模块名称、约定、已启用的插件、GAS/网络设置)。如果文件缺失,请继续。
根据请求和代码库确定所属领域。只有在两种合理解读会产生不同代码时才提问。
| 请求涉及…… | 前往 |
|---|---|
| AnimInstance 子类、线程安全更新、代理 | AnimInstance 和 Proxy |
| 播放/停止蒙太奇、跳转片段、结束回调 | 蒙太奇 |
| 通知、通知状态、分支点、通知时机 | 动画通知 |
| 曲线值、变形目标、曲线元数据 | 动画曲线 |
| 混合空间、状态机、瞄准偏移、分层混合 | 混合空间和状态机 |
| 关联动画层、按模式切换移动方式 | 关联动画图和层 |
| 根运动提取和模式 | 根运动 |
| 动作匹配、扭曲、IK Rig、Control Rig、变形器 | 5.8 动画插件 |
AnimInstance 和 Proxy
UAnimInstance(Animation/AnimInstance.h)分两个阶段运行。游戏线程:NativeUpdateAnimation — 可安全读取游戏状态。工作线程:NativeThreadSafeUpdateAnimation 和混合树求值。在游戏线程缓存游戏状态读取结果;在工作线程上只读取这些缓存值。
虚函数原文(AnimInstance.h:1436-1457 为 public,:1716-1719 为 protected):
virtual void NativeInitializeAnimation();
virtual void NativeUpdateAnimation(float DeltaSeconds);
virtual void NativeThreadSafeUpdateAnimation(float DeltaSeconds);
virtual void NativePostEvaluateAnimation();
virtual void NativeUninitializeAnimation();
virtual void NativeBeginPlay();
virtual FAnimInstanceProxy* CreateAnimInstanceProxy(); // protected
virtual void DestroyAnimInstanceProxy(FAnimInstanceProxy* InProxy); // protected
FAnimInstanceProxy(Public/Animation/AnimInstanceProxy.h)是工作线程数据容器。其重写点为 protected(:603-669):
virtual void Initialize(UAnimInstance* InAnimInstance);
virtual void PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds);
virtual void Update(float DeltaSeconds) {}
virtual bool Evaluate(FPoseContext& Output) { return false; }
virtual void PostUpdate(UAnimInstance* InAnimInstance) const;
virtual void Uninitialize(UAnimInstance* InAnimInstance);
通过受保护的模板 GetProxyOnGameThread<T>()(:1746)和 GetProxyOnAnyThread<T>()(:1769)访问代理。
// MyAnimInstance.h
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimInstance.h"
#include "Animation/AnimInstanceProxy.h"
#include "MyAnimInstance.generated.h"
class ACharacter;
class UCharacterMovementComponent;
USTRUCT()
struct FMyAnimInstanceProxy : public FAnimInstanceProxy
{
GENERATED_BODY()
FMyAnimInstanceProxy() = default;
explicit FMyAnimInstanceProxy(UAnimInstance* InAnimInstance)
: FAnimInstanceProxy(InAnimInstance) {}
// Written on the game thread in PreUpdate, read on the worker thread in Update.
FVector Velocity = FVector::ZeroVector;
float Speed = 0.f;
bool bIsFalling = false;
protected:
virtual void PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds) override;
virtual void Update(float DeltaSeconds) override;
};
UCLASS()
class MYGAME_API UMyAnimInstance : public UAnimInstance
{
GENERATED_BODY()
public:
virtual void NativeInitializeAnimation() override;
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
virtual void NativeThreadSafeUpdateAnimation(float DeltaSeconds) override;
virtual void NativeUninitializeAnimation() override;
protected:
virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override;
virtual void DestroyAnimInstanceProxy(FAnimInstanceProxy* InProxy) override;
UPROPERTY(Transient)
TObjectPtr<ACharacter> OwningCharacter;
UPROPERTY(Transient)
TObjectPtr<UCharacterMovementComponent> MovementComp;
UPROPERTY(Transient, BlueprintReadOnly, Category = "Locomotion")
float Speed = 0.f;
UPROPERTY(Transient, BlueprintReadOnly, Category = "Locomotion")
float Direction = 0.f;
UPROPERTY(Transient, BlueprintReadOnly, Category = "Locomotion")
bool bIsInAir = false;
};
// MyAnimInstance.cpp
#include "MyAnimInstance.h"
#include "GameFramework/Character.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Kismet/KismetMathLibrary.h"
void FMyAnimInstanceProxy::PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds)
{
FAnimInstanceProxy::PreUpdate(InAnimInstance, DeltaSeconds);
// Game thread: safe to touch the owning actor here.
if (const ACharacter* Character = Cast<ACharacter>(InAnimInstance->TryGetPawnOwner()))
{
const UCharacterMovementComponent* Movement = Character->GetCharacterMovement();
Velocity = Movement->Velocity;
bIsFalling = Movement->IsFalling();
}
}
void FMyAnimInstanceProxy::Update(float DeltaSeconds)
{
FAnimInstanceProxy::Update(DeltaSeconds);
Speed = Velocity.Size2D(); // Worker thread: proxy members only.
}
FAnimInstanceProxy* UMyAnimInstance::CreateAnimInstanceProxy()
{
return new FMyAnimInstanceProxy(this);
}
void UMyAnimInstance::DestroyAnimInstanceProxy(FAnimInstanceProxy* InProxy)
{
delete InProxy;
}
void UMyAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();
OwningCharacter = Cast<ACharacter>(TryGetPawnOwner());
if (OwningCharacter)
{
MovementComp = OwningCharacter->GetCharacterMovement();
}
}
void UMyAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
if (!OwningCharacter || !MovementComp)
{
return;
}
const FVector CurrentVelocity = MovementComp->Velocity;
Speed = CurrentVelocity.Size2D();
bIsInAir = MovementComp->IsFalling();
if (Speed > 3.f)
{
Direction = UKismetMathLibrary::NormalizedDeltaRotator(
CurrentVelocity.ToOrientationRotator(),
OwningCharacter->GetActorRotation()).Yaw;
}
}
void UMyAnimInstance::NativeThreadSafeUpdateAnimation(float DeltaSeconds)
{
Super::NativeThreadSafeUpdateAnimation(DeltaSeconds);
// Worker thread: read the proxy, never the owning actor. This runs before the
// proxy's Update(), so read what PreUpdate wrote, not what Update derives.
const FMyAnimInstanceProxy& Proxy = GetProxyOnAnyThread<FMyAnimInstanceProxy>();
Speed = Proxy.Velocity.Size2D();
bIsInAir = Proxy.bIsFalling;
}
void UMyAnimInstance::NativeUninitializeAnimation()
{
Super::NativeUninitializeAnimation();
OwningCharacter = nullptr;
MovementComp = nullptr;
}
使用 NeedsUpdate()(AnimInstance.h:512)查询待处理的更新状态;成员 bNeedsUpdate 已弃用。
蒙太奇
来源:Animation/AnimInstance.h、Animation/AnimMontage.h。签名原文(AnimInstance.h:626-796):
float Montage_Play(UAnimMontage* MontageToPlay, float InPlayRate = 1.f,
EMontagePlayReturnType ReturnValueType = EMontagePlayReturnType::MontageLength,
float InTimeToStartMontageAt = 0.f, bool bStopAllMontages = true);
// Same trailing params; override the asset's blend-in (FMontageBlendSettings adds BlendProfile and
// BlendMode, e.g. EMontageBlendMode::Inertialization)
float Montage_PlayWithBlendIn(UAnimMontage* MontageToPlay, const FAlphaBlendArgs& BlendIn, ...);
float Montage_PlayWithBlendSettings(UAnimMontage* MontageToPlay, const FMontageBlendSettings& BlendInSettings, ...);
void Montage_Stop(float InBlendOutTime, const UAnimMontage* Montage = NULL);
void Montage_Pause(const UAnimMontage* Montage = NULL);
void Montage_Resume(const UAnimMontage* Montage);
void Montage_JumpToSection(FName SectionName, const UAnimMontage* Montage = NULL);
void Montage_SetNextSection(FName SectionNameToChange, FName NextSection,
const UAnimMontage* Montage = NULL);
void Montage_SetPlayRate(const UAnimMontage* Montage, float NewPlayRate = 1.f);
bool Montage_IsPlaying(const UAnimMontage* Montage) const;
bool Montage_IsActive(const UAnimMontage* Montage) const;
bool Montage_GetIsStopped(const UAnimMontage* Montage) const;
float Montage_GetPosition(const UAnimMontage* Montage) const;
void Montage_SetPosition(const UAnimMontage* Montage, float NewPosition);
float Montage_GetBlendTime(const UAnimMontage* Montage) const;
float Montage_GetPlayRate(const UAnimMontage* Montage) const;
FName Montage_GetCurrentSection(const UAnimMontage* Montage = NULL) const;
void Montage_SetEndDelegate(FOnMontageEnded& InOnMontageEnded, UAnimMontage* Montage = NULL);
void Montage_SetBlendingOutDelegate(FOnMontageBlendingOutStarted& InOnMontageBlendingOut,
UAnimMontage* Montage = NULL);
EMontagePlayReturnType(AnimInstance.h:70)为 MontageLength 或 Duration。一旦开始混出,Montage_IsPlaying 和 Montage_IsActive 就会返回 false,Montage_GetIsStopped 则会返回 true,即使姿势仍在混合(Stop() 会将该实例从 ActiveMontagesMap 中移除,AnimInstance.cpp:3709)。混出开始时使用 OnMontageBlendingOut / Montage_SetBlendingOutDelegate,结束时使用 OnMontageEnded。委托类型(AnimInstance.h:79-80)为单播:
DECLARE_DELEGATE_TwoParams(FOnMontageEnded, UAnimMontage*, bool /*bInterrupted*/)
DECLARE_DELEGATE_TwoParams(FOnMontageBlendingOutStarted, UAnimMontage*, bool /*bInterrupted*/)
如需广播,请使用动态多播成员 OnMontageStarted、OnMontageEnded 和 OnMontageBlendingOut(:758-770)。
void UMyWeaponComponent::PlayAttackMontage(USkeletalMeshComponent* Mesh, UAnimMontage* Montage)
{
UAnimInstance* AnimInst = Mesh ? Mesh->GetAnimInstance() : nullptr;
if (!AnimInst || !Montage)
{
return;
}
// Play FIRST: the delegate setters resolve the active montage instance,
// which does not exist until Montage_Play has created it.
if (AnimInst->Montage_Play(Montage) <= 0.f)
{
return;
}
FOnMontageEnded EndDelegate;
EndDelegate.BindUObject(this, &UMyWeaponComponent::OnAttackEnded);
AnimInst->Montage_SetEndDelegate(EndDelegate, Montage);
FOnMontageBlendingOutStarted BlendOutDelegate;
BlendOutDelegate.BindUObject(this, &UMyWeaponComponent::OnAttackBlendingOut);
AnimInst->Montage_SetBlendingOutDelegate(BlendOutDelegate, Montage);
}
void UMyWeaponComponent::OnAttackEnded(UAnimMontage* Montage, bool bInterrupted) {}
void UMyWeaponComponent::OnAttackBlendingOut(UAnimMontage* Montage, bool bInterrupted) {}
USkeletalMeshComponent(Components/SkeletalMeshComponent.h):
UAnimInstance* GetAnimInstance() const; // :1111
void PlayAnimation(class UAnimationAsset* NewAnimToPlay, bool bLooping); // :1258
virtual void SetAnimInstanceClass(class UClass* NewClass); // :1096
void LinkAnimClassLayers(TSubclassOf<UAnimInstance> InClass); // :1194
void UnlinkAnimClassLayers(TSubclassOf<UAnimInstance> InClass); // :1205
UAnimInstance* GetLinkedAnimGraphInstanceByTag(FName InTag) const; // :1160
void SetAnimationMode(EAnimationMode::Type InAnimationMode,
bool bForceInitAnimScriptInstance = true); // :1246
PlayAnimation 会使组件进入单节点模式;SetAnimInstanceClass 会使组件进入 Animation Blueprint 模式。在同一个组件上混用这两种模式,会导致其中一种被静默丢弃。
多人游戏:使用 GAS 时,通过 UAbilityTask_PlayMontageAndWait::CreatePlayMontageAndWaitProxy(GameplayAbilities/Public/Abilities/Tasks/AbilityTask_PlayMontageAndWait.h:66)驱动蒙太奇——参见 ue-gameplay-abilities。不使用 GAS 时,应自行复制蒙太奇选择,并在复制回调中调用 Montage_Play;切勿针对每个网络角色分别调用。
动画通知
来源:Animation/AnimNotifies/AnimNotify.h、AnimNotifyState.h。重写以下准确签名:
// UAnimNotify (AnimNotify.h:85-86, :59)
virtual void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,
const FAnimNotifyEventReference& EventReference);
virtual void BranchingPointNotify(FBranchingPointNotifyPayload& BranchingPointPayload);
FString GetNotifyName() const; // BlueprintNativeEvent: override GetNotifyName_Implementation
// UAnimNotifyState (AnimNotifyState.h:74-80)
virtual void NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,
float TotalDuration, const FAnimNotifyEventReference& EventReference);
virtual void NotifyTick(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,
float FrameDeltaTime, const FAnimNotifyEventReference& EventReference);
virtual void NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,
const FAnimNotifyEventReference& EventReference);
Received_Notify(AnimNotify.h:62)和 Received_NotifyBegin / Received_NotifyTick / Received_NotifyEnd(AnimNotifyState.h:45-51)是 BlueprintImplementableEvent 入口点——应在 Blueprint 中实现,切勿在 C++ 中重写。
蒙太奇通知的时序按事件而定:FAnimNotifyEvent::MontageTickType(Public/Animation/AnimTypes.h:318)可以是 EMontageNotifyTickType::Queued(在求值阶段结束时触发——头文件指出它不适用于更改分段或蒙太奇位置),也可以是 BranchingPoint(遇到时触发,适用于分段更改)。原生通知会在其构造函数中将 bIsNativeBranchingPoint = true,从而强制走分支点路径(AnimNotify.h:123、AnimNotifyState.h:108)。
在 AnimInstance 外部使用 OnPlayMontageNotifyBegin / OnPlayMontageNotifyEnd(类型为 FPlayMontageAnimNotifyDelegate)绑定命名蒙太奇通知(AnimInstance.h:1820-1823)。
内置通知目录、完整的自定义通知和通知状态示例、FAnimNotifyEvent 字段及关联实例传播机制,请参阅 references/anim-notify-reference.md。
动画曲线
在 5.8 中,曲线通过 FName 寻址——不使用智能名称、曲线 UID 或映射查找。
// UAnimInstance (AnimInstance.h:1241-1273)
float GetCurveValue(FName CurveName) const;
bool GetCurveValue(FName CurveName, float& OutValue) const;
bool GetCurveValueWithDefault(FName CurveName, float DefaultValue, float& OutValue) const;
void SetMorphTarget(FName MorphTargetName, float Value);
// USkeletalMeshComponent (SkeletalMeshComponent.h:664-667)
bool GetCurveValue(FName CurveName, float DefaultValue, float& Value) const;
const FBlendedHeapCurve& GetAnimCurves() const;
每条曲线的标志(曲线是否驱动材质或变形目标)存储在骨架上的 CurveMetaData 中(Animation/Skeleton.h:387-467):GetCurveMetaData(FName)、AddCurveMetaData(FName CurveName, bool bTransact = true)、GetCurveMetaDataNames(TArray<FName>& OutNames)、SetCurveMetaDataMorphTarget(FName CurveName, bool bOverrideMorphTarget)。
混合空间与状态机
混合空间是由 AnimGraph 节点采样的资产;通过 AnimGraph 读取的 UPROPERTY 成员驱动它们。
| 资产类 | 头文件 | 用途 |
|---|---|---|
UBlendSpace | Animation/BlendSpace.h:470 | 双轴混合,通常是方向 x 速度 |
UBlendSpace1D | Animation/BlendSpace1D.h:19 | 单轴混合,通常是速度 |
UAimOffsetBlendSpace | Animation/AimOffsetBlendSpace.h:20 | 在基础姿势上叠加瞄准姿势 |
轴平滑使用 FInterpolationParameter(BlendSpace.h:80-110):InterpolationTime、DampingRatio、MaxSpeed,以及类型为 TEnumAsByte<EFilterInterpolationType> 的 InterpolationType —— 可选值为 BSIT_Average、BSIT_Linear、BSIT_Cubic、BSIT_EaseInOut、BSIT_ExponentialDecay、BSIT_SpringDamper(Engine/EngineTypes.h:1356)。
从 NativeInitializeAnimation(AnimInstance.h:1461-1473)将原生 C++ 绑定到已编译的状态机:
// CanStartMoving() and OnLandEntered() are members of UMyAnimInstance.
// DECLARE_DELEGATE_RetVal(bool, FCanTakeTransition) AnimInstance.h:118
// DECLARE_DELEGATE_ThreeParams(FOnGraphStateChanged,
// const struct FAnimNode_StateMachine&, int32, int32) AnimInstance.h:121
AddNativeTransitionBinding(FName("LocomotionSM"), FName("Idle"), FName("Walk"),
FCanTakeTransition::CreateUObject(this, &UMyAnimInstance::CanStartMoving),
FName("IdleToMoving"));
AddNativeStateEntryBinding(FName("LocomotionSM"), FName("Land"),
FOnGraphStateChanged::CreateUObject(this, &UMyAnimInstance::OnLandEntered));
运行时可通过 GetStateMachineIndex(FName MachineName)(:1202)、GetStateMachineInstanceFromName(FName MachineName)(:1191)和 GetInstanceStateWeight(int32 MachineIndex, int32 StateIndex)(:1116)进行查询。
完整的混合空间、状态机、逐骨骼分层混合和瞄准偏移设置,请参阅 references/locomotion-setup.md。
链接的 Anim Graph 与层
来源:Animation/AnimNode_LinkedAnimGraph.h、Animation/AnimNode_LinkedAnimLayer.h。
// UAnimInstance (AnimInstance.h:850-910)
virtual void LinkAnimClassLayers(TSubclassOf<UAnimInstance> InClass);
virtual void UnlinkAnimClassLayers(TSubclassOf<UAnimInstance> InClass);
UAnimInstance* GetLinkedAnimLayerInstanceByClass(TSubclassOf<UAnimInstance> InClass,
bool bCheckForChildClass = false) const;
void LinkAnimGraphByTag(FName InTag, TSubclassOf<UAnimInstance> InClass);
UAnimInstance* GetLinkedAnimGraphInstanceByTag(FName InTag) const;
LinkAnimClassLayers(nullptr) 会恢复默认的层实现。链接实例之间的通知流由 SetReceiveNotifiesFromLinkedInstances(bool bSet) 和 SetPropagateNotifiesToLinkedInstances(bool bSet)(:523-531)设置,也可以按节点通过 bReceiveNotifiesFromLinkedInstances / bPropagateNotifiesToLinkedInstances(AnimNode_LinkedAnimGraph.h:76-80)设置。SetUseMainInstanceMontageEvaluationData(bool bSet)(:537)可让链接层共享主实例的蒙太奇评估数据。
使用链接节点上的 PendingBlendInDuration / PendingBlendOutDuration(AnimNode_LinkedAnimGraph.h:60-67)平滑混合切换,也可以在代码中请求切换:
// AnimInstance.h:1006
AnimInst->RequestSlotGroupInertialization(FName("DefaultGroup"), 0.2f);
根运动
ERootMotionMode::Type(Animation/AnimEnums.h:27-42):NoRootMotionExtraction、IgnoreRootMotion、RootMotionFromEverything、RootMotionFromMontagesOnly。头文件指出,RootMotionFromEverything 不适用于联网多人游戏,而 RootMotionFromMontagesOnly 是联网时的推荐选项。
// AnimInstance.h:372, :1066, :1662
TEnumAsByte<ERootMotionMode::Type> RootMotionMode; // UPROPERTY(EditDefaultsOnly)
void SetRootMotionMode(TEnumAsByte<ERootMotionMode::Type> Value);
FRootMotionMovementParams ConsumeExtractedRootMotion(float Alpha);
// Suppress root motion for part of a montage (AnimMontage.h:562-564)
if (FAnimMontageInstance* Inst = AnimInst->GetActiveInstanceForMontage(Montage))
{
Inst->PushDisableRootMotion();
// ... later ...
Inst->PopDisableRootMotion();
}
蒙太奇根运动和 RootMotionSource 是两个独立系统:蒙太奇路径会将基于姿势的增量传递给移动组件,而 RootMotionSource 则会在没有动画关联的情况下应用脚本控制的移动。联网预测、校正以及 bAllowPhysicsRotationDuringAnimRootMotion(GameFramework/CharacterMovementComponent.h:1083)属于 ue-character-movement。
5.8 动画插件
除非另有说明,每个插件在 .uproject 中默认禁用;使用其类型时,请将模块添加到 Build.cs。
| 插件 / 模块 | 5.8 成熟度 | 关键类型和头文件 |
|---|---|---|
PoseSearch | 正式版 | FAnimNode_MotionMatching (PoseSearch/AnimNode_MotionMatching.h:18)、UPoseSearchDatabase (PoseSearch/PoseSearchDatabase.h:502);轨迹类型为 FTransformTrajectorySample (Runtime/Engine/Public/Animation/TrajectoryTypes.h:18) |
Chooser | 正式版 | UChooserTable (Chooser.h:22)、UChooserFunctionLibrary (ChooserFunctionLibrary.h:18) — 数据驱动的资源选择,通常用于为动作匹配提供输入 |
MotionWarping | 5.8 中为 Beta 版 | UMotionWarpingComponent (MotionWarpingComponent.h:100)、URootMotionModifier (RootMotionModifier.h:71);旋转偏移使用 AdditionalRotationOffset (RootMotionModifier.h:407) |
IKRig | 正式版,默认启用 | UIKRigDefinition (Rig/IKRigDefinition.h:206)、UIKRetargeter (Retargeter/IKRetargeter.h:70) — 运行时 IK 求解和动画重定向 |
ControlRig | 正式版,默认启用 | UControlRig (ControlRig.h:63)、FAnimNode_ControlRig (AnimNode_ControlRig.h:21) — 在 AnimGraph 中求值的程序化 Rig |
BlendStack | 正式版 | FAnimNode_BlendStack 和 FAnimNode_BlendStack_Standalone (BlendStack/AnimNode_BlendStack.h:272,150) — 动作匹配所基于的混合堆栈 |
OptimusCore(Deformer Graph) | 5.8 中为 Beta 版 | UOptimusDeformer (OptimusDeformer.h:132) — GPU 网格变形图 |
UAF | 5.8 中为实验性 | Plugins/Experimental/UAF/UAF,模块 UAF:UUAFRigVMAsset (AnimNextRigVMAsset.h:61)、UUAFComponent (Component/AnimNextComponent.h:77) — 后继动画框架 |
已弃用 — 请勿使用
| 请勿使用 | 在 5.8 中使用 | 来源 |
|---|---|---|
FSmartName, FSmartNameMapping, FSmartNameContainer | 普通的 FName 曲线名称 | Animation/SmartName.h:20,80,121 中的 UE_DEPRECATED(5.8) |
| Skeleton 智能名称曲线表 | USkeleton 上的 CurveMetaData 访问器 | Animation/Skeleton.h:505 中的 UE_DEPRECATED(5.7) |
AnimCurveUID | FName 曲线名称 | Animation/Skeleton.h:384 中的 UE_DEPRECATED(5.7) |
UAnimInstance::bNeedsUpdate | NeedsUpdate() | Animation/AnimInstance.h:389 中的 UE_DEPRECATED(5.7) |
USkeletalMeshComponent::SetAnimClass | SetAnimInstanceClass | Components/SkeletalMeshComponent.h:1084 中的 UE_DEPRECATED(5.5) |
USkeletalMeshComponent::AnimCurves 成员 | GetAnimCurves() / GetCurveValue() | Components/SkeletalMeshComponent.h:470 中的 UE_DEPRECATED(5.6) |
UAnimSequence::RetargetSourceAsset 成员 | GetRetargetSourceAsset / SetRetargetSourceAsset | Animation/AnimSequence.h:305 中的 UE_DEPRECATED(5.5) |
FTrajectorySample | FTransformTrajectorySample | Public/Animation/MotionTrajectoryTypes.h:10 中的 UE_DEPRECATED(5.6) |
FPoseSearchQueryTrajectorySample | FTransformTrajectorySample | PoseSearch/PoseSearchTrajectoryTypes.h:16 中的 UE_DEPRECATED(5.6) |
FPoseSearchDatabaseSequence, FPoseSearchDatabaseBlendSpace | FPoseSearchDatabaseAnimationAsset | PoseSearch/PoseSearchDatabase.h:228 中的 UE_DEPRECATED(5.7) |
EMotionWarpRotationType::OppositeDefault / OppositeFacing | AdditionalRotationOffset | MotionWarping/RootMotionModifier.h:309,312 中的 UE_DEPRECATED(5.8) |
FAnimInstanceProxy::GetSlotInertializationRequest | GetSlotInertializationRequestData | Public/Animation/AnimInstanceProxy.h:444 中的 UE_DEPRECATED(5.5) |
SetSubInstanceClassByTag, GetSubInstanceByTag | LinkAnimGraphByTag, GetLinkedAnimGraphInstanceByTag | Animation/AnimInstance.h:860,845 中的 UE_DEPRECATED(4.24) |
SetLayerOverlay, ClearLayerOverlay | LinkAnimClassLayers, UnlinkAnimClassLayers | Animation/AnimInstance.h:868,880 中的 UE_DEPRECATED(4.24) |
GetLayerSubInstanceByClass | GetLinkedAnimLayerInstanceByClass | Animation/AnimInstance.h:906 中的 UE_DEPRECATED(4.24) |
常见错误
在 NativeThreadSafeUpdateAnimation 中访问所属 Actor: 此函数在工作线程上运行,因此 TryGetPawnOwner()、组件查询和 Trace 在这里都不安全。请在 NativeUpdateAnimation 或 FAnimInstanceProxy::PreUpdate 中缓存所需数据,并且在工作线程上只读取这些成员。
在 Montage_Play 之前绑定蒙太奇委托: Montage_SetEndDelegate 和 Montage_SetBlendingOutDelegate 会查找当前激活的蒙太奇实例,而此时该实例尚不存在。请先调用 Montage_Play,确认返回值大于零,然后再绑定委托。
在 C++ 中重写 Received_Notify: 它是一个 BlueprintImplementableEvent。请改为重写 Notify(USkeletalMeshComponent*, UAnimSequenceBase*, const FAnimNotifyEventReference&)。
从排队的通知中跳转片段: 排队的通知会在求值阶段之后触发,因此从通知中调用 Montage_JumpToSection 会晚一帧。请设置 bIsNativeBranchingPoint = true,并重写 BranchingPointNotify 来控制片段。
通过智能名称或 UID 查找曲线: FSmartName、FSmartNameMapping 和 AnimCurveUID 均已弃用。请将 FName 传给 GetCurveValue,并将每条曲线的标志保存在 CurveMetaData 中。
将代理重写声明为 public: FAnimInstanceProxy 中的 Initialize、PreUpdate、Update、Evaluate 和 PostUpdate 都是 protected;UAnimInstance 中的 CreateAnimInstanceProxy / DestroyAnimInstanceProxy 也是如此。请保持相同的访问级别,否则重写将无法编译。
跳过基类调用: 每个 Native* 重写都要调用对应的 Super:: 形式,每个代理重写都要调用 FAnimInstanceProxy::<Name>;基类实现负责驱动蒙太奇更新、通知队列和代理簿记。
相关技能
ue-character-movement—UCharacterMovementComponent、RootMotionSource、网络根运动预测与校正。ue-gameplay-abilities—UAbilityTask_PlayMontageAndWait、GAS 蒙太奇复制、由技能驱动的动画。ue-actor-component-architecture—USkeletalMeshComponent设置、附加、组件 Tick 顺序。ue-sequencer-cinematics— Level Sequence 动画轨道,以及在骨骼网格体上的电影级播放。ue-mass-entity— 通过 Mass 表示而非逐个 Actor 的 AnimInstance 实现大规模人群动画。ue-cpp-foundations— 委托绑定、UPROPERTY/UFUNCTION说明符、TObjectPtr。ue-niagara-effects— 由通知生成的 Niagara 系统,以及骨骼网格体数据接口。ue-audio-system— UAudioComponent、MetaSounds、子混音、衰减与并发ue-mover— Mover 插件:移动模式、分层移动与回滚网络