UAnimInstance
创建C++类需要继承父类UAnimInstance:
UCLASS()
class QIANGGEDAIWO_API UMyAnimInstance : public UAnimInstance
之后使用UMyAnimInstance 来创建动画蓝图。
蓝图中BlueprintUpdateAnimation节点是游戏每帧中对状态属性的更新。在C++中对应虚函数
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
获取角色类API
尝试获取当前使用该动画示例的角色接口:
if(!MyCharacterBase)
{
MyCharacterBase = Cast<ALGCharacterBase>(TryGetPawnOwner());//尝试获取当前使用该动画示例的角色
return;
}
获取角色移动速度
Speed = MyCharacterBase->GetVelocity().Size2D();//只取xy平面上的速度
获取Rotation的方向向量
使用旋转矩阵RotationMatrix来计算
FRotator NewRot(0,GetControlRotation().Yaw,0);
FRotationMatrix RotationMatrix(NewRot);
AddMovementInput(RotationMatrix.GetUnitAxis(EAxis::Type::X)*Vector2D.Y);
AddMovementInput(RotationMatrix.GetUnitAxis(EAxis::Type::Y)*Vector2D.X);
需要修改角色移动组件CharacterMovementComponent的功能时
我们直接继承虚幻引擎的移动组件类,然后在其子类中修改相应功能即可,
class QIANGGEDAIWO_API UMyCharacterMovementComponent : public UCharacterMovementComponent
之后我们的角色类挂载的移动功能组件需要替换成我们的自定义移动功能组件,但角色的构造函数需要特殊处理一下,如下文。
虚幻引擎中的类凡是继承的U类的类,其构造函数要么是无参的,要么则传入一个初始化构造器参数,否则虚幻引擎无法处理,
//无参
AMyCharacterBase();
//带有一个初始化构造器参数
AMyCharacterBase(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
然后角色的构造函数的实现代码如下
// Sets default values
AMyCharacterBase::AMyCharacterBase(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer.SetDefaultSubobjectClass<UMyCharacterMovementComponent>(CharacterMovementComponentName))
//希望父类构建时,走带有构造器的函数进行构建,并且传给它ObjectInitializer时顺便将UMyCharacterMovementComponent组件的类设置为我们自己的移动组件类
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
希望父类构建时,走带有构造器的函数进行构建,并且传给它ObjectInitializer时顺便将UMyCharacterMovementComponent组件的类设置为我们自己的移动组件类。这样就将子类蓝图中的移动组件替换为我们自己的了。
自定义相机管理器
创建相机管理器类需要继承APlayerCameraManager类
UCLASS()
class QIANGGEDAIWO_API AMyPlayerCameraManager : public APlayerCameraManager
然后在玩家控制器PlayerController中进行挂载
AMyPlayerController::AMyPlayerController()
{
PlayerCameraManagerClass = AMyPlayerCameraManager::StaticClass();
}
小提示:相机管理器中的UpdateCamera方法相当于tick可以每帧修改逻辑,如下重写
protected:
virtual void UpdateCamera(float DeltaTime) override;
实现:
void AMyPlayerCameraManager::UpdateCamera(float DeltaTime)
{
自定义逻辑
//执行父类的UpdateCamera时就会渲染相机,所以自定义逻辑需要写在这之前
Super::UpdateCamera(DeltaTime);
}
相机平滑移动
情景是我们蹲下时,相机瞬间下降了我们蹲下的这段距离,要使这个过程平滑。
已知蹲下时相机弹簧臂会固定的下降48个单位,我们可以在触发蹲下时,为弹簧臂增加48个单位的相对偏移,并将这个值设为变量,使其平滑归零,实现效果。站起来则为相反逻辑。
值的平滑过渡会使用插值函数
插值函数
FMath::FInterpTo(CurrentValue,TargetValue,DeltaTime,interpSpeed);
CurrentValue当前的值
TargetValue目标值
DeltaTime时间增量
interpSpeed插值速度
protected:
virtual void UpdateCamera(float DeltaTime) override;
float OffsetSpringZ;//相机Z轴相对偏移量
bool PreTickIsCourch;//缓存上一帧的是否蹲下状态
void ALGPlayerCameraManager::UpdateCamera(float DeltaTime)
{
ALGPlayerCharacter* player = Cast<ALGPlayerCharacter>(GetOwningPlayerController()->GetPawn());
if(player)
{
//蹲起时相机平滑过度
if(player->GetIsCrouch() && !PreTickIsCourch)
{
OffsetSpringZ = 48.f;
}
else if(!player->GetIsCrouch() && PreTickIsCourch)
{
OffsetSpringZ = -48.f;
}
PreTickIsCourch = player->GetIsCrouch();
OffsetSpringZ = FMath::FInterpTo(OffsetSpringZ,0,DeltaTime,10);
player->GetSpringArmComponent()->SetRelativeLocation(FVector(0,0,OffsetSpringZ));
}
Super::UpdateCamera(DeltaTime);
}
动画通知
当动画资产播放到某一帧时需要执行某段逻辑时(可以是播放音效,播放特效,触发事件等等),需要使用动画通知功能。在动画资产的通知轨道中新建并添加通知,例如我新建了一个命名为RelaxEnd的通知,如下图
然后在C++动画实例类(UAnimInstance)中添加相应函数,这个函数有以下约束:
1.使用UFUNCTION()标识。
2.函数前缀为“AnimNotify_”
举例如下
protected:
UFUNCTION()
void AnimNotify_RelaxEnd();
void UMyAnimInstance::AnimNotify_RelaxEnd()
{
//执行需要的逻辑
}
随机播放动画资产节点
在动画蓝图中添加RandomSequencePlayer节点,并为他的成员属性Entries添加成员属性也就是动画资产,它会在添加的动画资产中随机选则一个进行输出。