mcpField
U
ue-animation-system

ue-animation-system

github.com/quodsoler开发4191.2k 次安装4 周前更新
代码仓库

关于 ue-animation-system

面向 UE 5.8 项目的动画系统开发技能,汇集运行时动画 API 与动画插件的参考。内容包括动画实例、蒙太奇、通知、曲线、混合空间、状态机及动画层。

主要功能

  1. 01动画实例与工作线程代理
  2. 02蒙太奇播放及结束回调
  3. 03动画通知与通知状态
  4. 04曲线、混合空间和状态机
  5. 05链接动画图层与根运动

适用场景

  1. 01实现线程安全的动画更新
  2. 02播放蒙太奇并处理混合结束
  3. 03创建动画通知以触发游戏逻辑
  4. 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 成员驱动它们。

资产类头文件用途
UBlendSpaceAnimation/BlendSpace.h:470双轴混合,通常是方向 x 速度
UBlendSpace1DAnimation/BlendSpace1D.h:19单轴混合,通常是速度
UAimOffsetBlendSpaceAnimation/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) — 数据驱动的资源选择,通常用于为动作匹配提供输入
MotionWarping5.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 网格变形图
UAF5.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)
AnimCurveUIDFName 曲线名称Animation/Skeleton.h:384 中的 UE_DEPRECATED(5.7)
UAnimInstance::bNeedsUpdateNeedsUpdate()Animation/AnimInstance.h:389 中的 UE_DEPRECATED(5.7)
USkeletalMeshComponent::SetAnimClassSetAnimInstanceClassComponents/SkeletalMeshComponent.h:1084 中的 UE_DEPRECATED(5.5)
USkeletalMeshComponent::AnimCurves 成员GetAnimCurves() / GetCurveValue()Components/SkeletalMeshComponent.h:470 中的 UE_DEPRECATED(5.6)
UAnimSequence::RetargetSourceAsset 成员GetRetargetSourceAsset / SetRetargetSourceAssetAnimation/AnimSequence.h:305 中的 UE_DEPRECATED(5.5)
FTrajectorySampleFTransformTrajectorySamplePublic/Animation/MotionTrajectoryTypes.h:10 中的 UE_DEPRECATED(5.6)
FPoseSearchQueryTrajectorySampleFTransformTrajectorySamplePoseSearch/PoseSearchTrajectoryTypes.h:16 中的 UE_DEPRECATED(5.6)
FPoseSearchDatabaseSequence, FPoseSearchDatabaseBlendSpaceFPoseSearchDatabaseAnimationAssetPoseSearch/PoseSearchDatabase.h:228 中的 UE_DEPRECATED(5.7)
EMotionWarpRotationType::OppositeDefault / OppositeFacingAdditionalRotationOffsetMotionWarping/RootMotionModifier.h:309,312 中的 UE_DEPRECATED(5.8)
FAnimInstanceProxy::GetSlotInertializationRequestGetSlotInertializationRequestDataPublic/Animation/AnimInstanceProxy.h:444 中的 UE_DEPRECATED(5.5)
SetSubInstanceClassByTag, GetSubInstanceByTagLinkAnimGraphByTag, GetLinkedAnimGraphInstanceByTagAnimation/AnimInstance.h:860,845 中的 UE_DEPRECATED(4.24)
SetLayerOverlay, ClearLayerOverlayLinkAnimClassLayers, UnlinkAnimClassLayersAnimation/AnimInstance.h:868,880 中的 UE_DEPRECATED(4.24)
GetLayerSubInstanceByClassGetLinkedAnimLayerInstanceByClassAnimation/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 插件:移动模式、分层移动与回滚网络

评论

支持 Markdown