虚幻c++动画
例如,一个角色以每秒 300 个单位的速度向前跑,并且每秒向下坠落 50 个单位(因为刚从悬崖跳下),它的速度向量可能是。可以安全地跳过这一帧的初始化,等待下一帧或下一次更新时再尝试获取。这是一个合法的、暂时的运行时状态,而不是一个代码错误。它表示的是角色移动组件在当前帧的加速度矢量。就是记录空闲时间,是否达到阈值,达到就状态转移。进行的、线程安全的属性更新和逻辑计算。,只使用 X 和 Y 分量来
视频学习:2-9_哔哩哔哩_bilibili
整体结构

创建好后,编辑UWarriorCharacterAnimInstance类
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "AnimInstances/WarriorBaseAnimInstance.h"
#include "WarriorCharacterAnimInstance.generated.h"
class AWarriorBaseCharacter;
class UCharacterMovementComponent;
/**
*
*/
UCLASS()
class WARRIOR_API UWarriorCharacterAnimInstance : public UWarriorBaseAnimInstance
{
GENERATED_BODY()
public:
virtual void NativeInitializeAnimation() override;
virtual void NativeThreadSafeUpdateAnimation(float DeltaSeconds) override;
protected:
UPROPERTY()
AWarriorBaseCharacter* OwningCharacter;
UPROPERTY()
UCharacterMovementComponent* OwningMovementComponent;
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "AnimData|LocomotionData")
float GroundSpeed;//角色速度
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "AnimData|LocomotionData")
bool bHasAcceleration;//是否有加速度
};
-
NativeInitializeAnimation: 一次性的初始化设置。 -
NativeThreadSafeUpdateAnimation: 每帧进行的、线程安全的属性更新和逻辑计算。
// Fill out your copyright notice in the Description page of Project Settings.
#include "AnimInstances/WarriorCharacterAnimInstance.h"
#include "Characters/WarriorBaseCharacter.h"
#include "GameFramework/CharacterMovementComponent.h"
void UWarriorCharacterAnimInstance::NativeInitializeAnimation()
{
OwningCharacter = Cast<AWarriorBaseCharacter>(TryGetPawnOwner());
if (OwningCharacter)
{
OwningMovementComponent = OwningCharacter->GetCharacterMovement();
}
}
void UWarriorCharacterAnimInstance::NativeThreadSafeUpdateAnimation(float DeltaSeconds)
{
if (!OwningCharacter || !OwningMovementComponent)
{
return;
}
GroundSpeed = OwningCharacter->GetVelocity().Size2D();
bHasAcceleration = OwningMovementComponent->GetCurrentAcceleration().SizeSquared2D() > 0.f;
}
这里使用if而不是check检测原因
NativeInitializeAnimation 被调用的时机非常早。此时,OwningCharacter有可能还未被有效设置。这是一个合法的、暂时的运行时状态,而不是一个代码错误。使用 if 可以安全地跳过这一帧的初始化,等待下一帧或下一次更新时再尝试获取。
check 应该用于验证那些在逻辑上绝对不应该发生的情况。如果这些情况发生了,说明代码本身存在 bug,继续运行下去毫无意义,甚至更危险。
-
GetVelocity():
这个方法返回一个FVector,表示角色的速度。一个FVector包含三个分量:-
X:通常代表前后方向(Forward/Backward)。 -
Y:通常代表左右方向(Right/Left)。 -
Z:代表上下方向(Up/Down)。
例如,一个角色以每秒 300 个单位的速度向前跑,并且每秒向下坠落 50 个单位(因为刚从悬崖跳下),它的速度向量可能是
(300, 0, -50)。 -
-
Size2D():它的计算公式是:
√(X² + Y²)(即二维的勾股定理)。这个函数会忽略掉向量的 Z 分量,只使用 X 和 Y 分量来计算长度。 -
GetCurrentAcceleration()返回的是一个标准的FVector,包含 X, Y, Z 三个分量。它表示的是角色移动组件在当前帧的加速度矢量。 -
SizeSquared2D():计算向量二维长度的平方。(X² + Y²)
创建动画蓝图

创建混合空间

设置最大速度,闲暇和跑步动画

回到动画蓝图创建状态机


| 特性 | 混合空间(Blend Space) | 状态机(State Machine) |
|---|---|---|
| 驱动方式 | 连续变化的参数(如 Speed, Direction) | 离散的状态和布尔条件(如 bIsJumping, bIsInCombat) |
| 最佳用途 | 处理量变(平滑过渡,如速度变化、方向变化) | 处理质变(状态切换,如落地、起跳、死亡) |
| 核心思想 | “混合” | “切换” |
最后给角色类mesh设置动画蓝图

使用c++完成状态过渡条件
添加一个状态


#pragma once
#include "CoreMinimal.h"
#include "AnimInstances/WarriorCharacterAnimInstance.h"
#include "WarriorHeroAnimInstance.generated.h"
class AWarriorHeroCharacter;
/**
*
*/
UCLASS()
class WARRIOR_API UWarriorHeroAnimInstance : public UWarriorCharacterAnimInstance
{
GENERATED_BODY()
public:
virtual void NativeInitializeAnimation() override;
virtual void NativeThreadSafeUpdateAnimation(float DeltaSeconds) override;
protected:
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "AnimData|Refrences")
AWarriorHeroCharacter* OwningHeroCharacter;
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "AnimData|LocomotionData")
bool bShouldEnterRelaxState;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "AnimData|LocomotionData")
float EnterRelaxtStateThreshold = 5.f;
float IdleElpasedTime;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "AnimInstances/Hero/WarriorHeroAnimInstance.h"
#include "Characters/WarriorHeroCharacter.h"
void UWarriorHeroAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();
if (OwningCharacter)
{
OwningHeroCharacter = Cast<AWarriorHeroCharacter>(OwningCharacter);
}
}
void UWarriorHeroAnimInstance::NativeThreadSafeUpdateAnimation(float DeltaSeconds)
{
Super::NativeThreadSafeUpdateAnimation(DeltaSeconds);
if (bHasAcceleration) {
IdleElpasedTime = 0.f;
bShouldEnterRelaxState = false;
}
else
{
IdleElpasedTime += DeltaSeconds;
bShouldEnterRelaxState = (IdleElpasedTime >= EnterRelaxtStateThreshold);
}
}
就是记录空闲时间,是否达到阈值,达到就状态转移
更多推荐
所有评论(0)