UE5 C++(十六)— Timeline的使用

2024-01-10 13:32:33

介绍

这里有官方文档介绍比较详细,我这边简单描述,重在实践。

时间轴(Timeline)可以实现从事件中播放基于时间的动画,这些事件可以沿着时间轴在关键帧处触发。可以使用时间轴来处理简单的非动画任务,例如开门、更改光源或对场景中的Actor执行其他以时间为中心的操纵。

关键组件:UTimelineComponent
包含一系列的 事件(events)、 浮点数(floats)、向量(vectors) 或 颜色(colors) 及其关联的关键帧。这些内容继承自UActorComponents

创建Timeline时间轴

在蓝图中创建

在这里插入图片描述
双击后可以添加浮点曲线等
在这里插入图片描述

在C++中创建

创建一个继承于Actor的C++类 MyTimelineActor,在这个类里写Timeline相关逻辑。在这里插入图片描述
MyTimelineActor.h

#pragma once

#include "CoreMinimal.h"
#include "Components/TimelineComponent.h"
#include "GameFramework/Actor.h"
#include "MyTimelineActor.generated.h"

UCLASS()
class DEMO_API AMyTimelineActor : public AActor
{
	GENERATED_BODY()

public:
	// Sets default values for this actor's properties
	AMyTimelineActor();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// 浮点数曲线
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyCurve")
	UCurveFloat *MyCurveFloat;
	// 时间轴组件
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MySceneComponent")
	UTimelineComponent *MyTimeline;

	// 声明时间轴回调函数
	FOnTimelineFloat TimelineCallback;
	// 声明时间轴结束事件  时间轴事件(FOnTimelineEvent)是动态委托,为时间轴组件提供处理事件的能力
	FOnTimelineEvent TimelineFinishedCallback;

	// 时间轴开始函数
	UFUNCTION(BlueprintCallable, Category = "MyTimeline")
	void TimelineStart(float Value);
	// 时间轴结束函数
	UFUNCTION(BlueprintCallable, Category = "MyTimeline")
	void TimelineFinished();
};

MyTimelineActor.cpp


#include "MyTimelineActor.h"

// Sets default values
AMyTimelineActor::AMyTimelineActor()
{
	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	MyTimeline = CreateDefaultSubobject<UTimelineComponent>(TEXT("MyTimeline"));

}

// Called when the game starts or when spawned
void AMyTimelineActor::BeginPlay()
{
	Super::BeginPlay();

	TimelineCallback.BindUFunction(this, FName("TimelineStart"));
	TimelineFinishedCallback.BindUFunction(this, FName("TimelineFinished"));
	// 绑定时间轴曲线
	MyTimeline->AddInterpFloat(MyCurveFloat, TimelineCallback);
	// 
	MyTimeline->SetLooping(false);
	MyTimeline->PlayFromStart();
	MyTimeline->Play();
	MyTimeline->SetTimelineFinishedFunc(TimelineFinishedCallback);
}

// Called every frame
void AMyTimelineActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}

void AMyTimelineActor::TimelineStart(float Value)
{
	UE_LOG(LogTemp, Warning, TEXT("TimelineStart"));
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("TimelineStart")));
}
void AMyTimelineActor::TimelineFinished()
{
	UE_LOG(LogTemp, Warning, TEXT("TimelineFinished"));
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("TimelineFinished")));
}

编译之后,创建浮点曲线
在这里插入图片描述
这里添加的浮点曲线,相当于蓝图中添加的浮点曲线
在这里插入图片描述
右键,添加关键帧
在这里插入图片描述
保存之后,创建MyTimelineActor的蓝图类
在这里插入图片描述
添加刚才创建的浮点曲线
在这里插入图片描述
编译,保存之后,拖到场景中运行,打印日志
在这里插入图片描述

在这里插入图片描述

使用Timeline实现开关门

拷贝引用 门模型:/Script/Engine.StaticMesh’/Game/StarterContent/Architecture/Wall_400x400.Wall_400x400’
在这里插入图片描述
MyTimelineActor.h


#pragma once

#include "CoreMinimal.h"
#include "Components/TimelineComponent.h"
// 引入组件
#include "Components/SceneComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Components/BoxComponent.h"
#include "MyCharacter.h"
#include "GameFramework/Actor.h"
#include "MyTimelineActor.generated.h"

UCLASS()
class DEMO_API AMyTimelineActor : public AActor
{
	GENERATED_BODY()

public:
	// Sets default values for this actor's properties
	AMyTimelineActor();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// 浮点数曲线
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyCurve")
	UCurveFloat *MyCurveFloat;
	// 时间轴组件
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyScene")
	UTimelineComponent *MyTimeline;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyScene")
	USceneComponent *MyScene;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyScene")
	UStaticMeshComponent *MyStaticMesh;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyScene")
	UBoxComponent *MyBox;

	//声明绑定碰撞函数
	UFUNCTION()
	void BeginOverlapFunction(UPrimitiveComponent *OverlappedComponent, AActor *OtherActor, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult &SweepResult);
	UFUNCTION()
	void EndOverlapFunction(UPrimitiveComponent *OverlappedComponent, AActor *OtherActor, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex);

	// 声明时间轴回调函数
	FOnTimelineFloat TimelineCallback;
	// 声明时间轴结束事件  时间轴事件(FOnTimelineEvent)是动态委托,为时间轴组件提供处理事件的能力
	FOnTimelineEvent TimelineFinishedCallback;

	// 时间轴开始函数
	UFUNCTION(BlueprintCallable, Category = "MyTimeline")
	void TimelineStart(float Value);
	// 时间轴结束函数
	UFUNCTION(BlueprintCallable, Category = "MyTimeline")
	void TimelineFinished();

	
};

MyTimelineActor.h

// Fill out your copyright notice in the Description page of Project Settings.

#include "MyTimelineActor.h"

// Sets default values
AMyTimelineActor::AMyTimelineActor()
{
	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	MyTimeline = CreateDefaultSubobject<UTimelineComponent>(TEXT("MyTimeline"));
	MyScene = CreateDefaultSubobject<USceneComponent>(TEXT("MyScene"));
	MyStaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MyStaticMesh"));
	MyBox = CreateDefaultSubobject<UBoxComponent>(TEXT("MyBox"));
	RootComponent = MyScene;
	MyStaticMesh->SetupAttachment(MyScene);
	MyBox->SetupAttachment(MyScene);
	MyBox->SetRelativeLocation(FVector(200.f, 0.f, 0.f));
	MyBox->SetBoxExtent(FVector(200.f, 80.f, 100.f));

	// note: 这段代码会导致UE5崩溃,原因未知 所以静态Mesh我在蓝图手动添加
	//  	// 添加门的模型
	//  	static ConstructorHelpers::FObjectFinder<UStaticMesh> TempStaticMesh(TEXT("/Script/Engine.StaticMesh'/Game/StarterContent/Architecture/Wall_400x400.Wall_400x400'"));
	//  	if (TempStaticMesh.Succeeded())
	//  	{
	//  		MyStaticMesh->SetStaticMesh(TempStaticMesh.Object);
	//  	}
}

// Called when the game starts or when spawned
void AMyTimelineActor::BeginPlay()
{
	Super::BeginPlay();

	TimelineCallback.BindUFunction(this, FName("TimelineStart"));
	TimelineFinishedCallback.BindUFunction(this, FName("TimelineFinished"));
	// 绑定时间轴曲线
	MyTimeline->AddInterpFloat(MyCurveFloat, TimelineCallback);
	//
	// MyTimeline->SetLooping(false);
	// MyTimeline->PlayFromStart();
	// MyTimeline->Play();
	MyTimeline->SetTimelineFinishedFunc(TimelineFinishedCallback);

	MyBox->OnComponentBeginOverlap.AddDynamic(this, &AMyTimelineActor::BeginOverlapFunction);
	MyBox->OnComponentEndOverlap.AddDynamic(this, &AMyTimelineActor::EndOverlapFunction);
}

// Called every frame
void AMyTimelineActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}

void AMyTimelineActor::TimelineStart(float Value)
{
	UE_LOG(LogTemp, Warning, TEXT("TimelineStart"));
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("TimelineStart")));
	// 旋转门 动画
	float YawRotation = FMath::Lerp(0.f, 90.f, Value);
	MyStaticMesh->SetRelativeRotation(FRotator(0.f, YawRotation, 0.f));
}
void AMyTimelineActor::TimelineFinished()
{
	UE_LOG(LogTemp, Warning, TEXT("TimelineFinished"));
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("TimelineFinished")));
}

void AMyTimelineActor::BeginOverlapFunction(UPrimitiveComponent *OverlappedComponent, AActor *OtherActor, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult &SweepResult)
{
	AMyCharacter *MyCharacter = Cast<AMyCharacter>(OtherActor);
	UE_LOG(LogTemp, Warning, TEXT("BeginOverlapFunction"));
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("BeginOverlapFunction")));
	if (MyCharacter)
	{
		MyTimeline->PlayFromStart();
	}
}
void AMyTimelineActor::EndOverlapFunction(UPrimitiveComponent *OverlappedComponent, AActor *OtherActor, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex)
{
	AMyCharacter *MyCharacter = Cast<AMyCharacter>(OtherActor);
	if (MyCharacter)
	{
		MyTimeline->ReverseFromEnd();
	}
}

编译之后,打开蓝图BP_MyTimelineActor ,调整一下
在这里插入图片描述
在这里插入图片描述
然后拖到场景中,摆放一下位置
在这里插入图片描述
点击运行,人物接触时门自动打开
在这里插入图片描述

文章来源:https://blog.csdn.net/qq_40120946/article/details/135498015
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。