本教程演示如何使用 时间轴 蓝图来创建基于距离的开门动画。

创建门Actor
-
首先,点击 新建(New) > 游戏(Games) > 空白(Blank) > 蓝图(Blueprint) 创建名为 TimelineDoorActor 的项目,并启用 初学者内容包(Starter Content)。
-
点击 添加/导入(Add/Import) 按钮新建蓝图 Actor 类,将其命名为 BP_DoorActor。
-
从内容浏览器中双击该BP_Door Actor在蓝图编辑器中打开,然后打开 类默认值(Class Defaults)。
-
下一步,在 组件(Components) 选项卡中点击 添加组件(Add Component) 按钮,选择 静态网格体(Static Mesh) 添加新的 静态网格体组件(Static Mesh Component)。
-
右键点击你的静态网格体组件,选择 重命名(Rename),将其重命名为 DoorFrame。
-
下一步,在 组件(Components) 选项卡中点击 添加组件(Add Component) 按钮,选择 静态网格体(Static Mesh) 添加新的 静态网格体组件(Static Mesh Component)。(重复步骤3)
-
右键点击你的静态网格体组件,选择重命名(Rename),将其重命名为 Door。
-
点击添加组件(Add Component),从下拉菜单中选择 盒体碰撞(Box Collision),将其重命名为 Box。
-
下一步,打开事件图表,右键点击 图表,从 蓝图上下文菜单(Blueprint Context Menu) 中选择 添加时间轴(Add Timeline)。将你的时间轴命名为 DoorTimelineComponent。
此时,BP_DoorActor的类默认值应如下例中所示:

设置门静态网格体
接下来,你需要设置 组件(Components) 选项卡的附件层级。
你还需要设置静态网格体资产,直观地表示你的 DoorFrame 和 Door 静态网格体组件。
-
从 BP_DoorActor 的组件(Components)选项卡中,选择 DoorFrame 静态网格体并将其拖动到 DefaultSceneRoot组件 上,使其成为新的 根组件。
-
接下来,在组件(Components)选项卡中选择 DoorFrame 静态网格体,从 细节面板(Details panel) 中将静态网格体更改为 SM_DoorFrame。
-
接下来,从组件(Components)面板中选择DoorMesh组件。导航至细节面板,将静态网格体更改为 SM_Door。
-
然后导航至 变换(Transform) 类别,将 Y位置(Y Location) 值更改为 45.0。
-
点击 保存(Save) 和 编译(Compile),将这些更改保存到Bp_DoorActor。
创建时间轴浮点轨道
时间轴组件需要时间轴曲线来描述其移动动画。每个轨道都可以包含多个键,用于定义时间和值。曲线内插这些键,以计算时间轴中任何点的值。
-
首先,在事件图表中双击DoorTimelineComponent,打开时间轴编辑器。
-
点击 添加浮点曲线(Add Float Curve) 向该轨道添加新曲线,将该曲线命名为 DoorRotationZ。
-
右键点击,向浮点曲线轨道添加两个键。两个键的值分别为(0,0)和(5,90)。
-
按住Shift键并选中这两个键,点击右键,从 键插值(Key Interpolation) 下拉菜单中选择 自动(Auto) 插值。
-
保存你的浮点轨道。
更新事件轨道逻辑
现在你需要创建更新逻辑,以旋转你的门静态网格体。
-
导航至BP_DoorActor的组件(Components)选项卡,将门静态网格体拖动到事件图表上
-
拖移门引脚,从操作上下文菜单中选择 SetRelativeRotation。
-
右键点击事件图表,从上下文菜单中选择 制作旋转体(Make Rotator)。
-
在 DoorTimelineComponent 节点上,拖动 Door Rotation Z 浮点引脚,将其连接至 Make Rotator 节点的 Z(Yaw) 引脚。
-
在 DoorTimelineComponent 节点上,拖移 更新(Update) 引脚,将其连接至 SetRelativeRotation 节点的输入执行引脚。
-
在 Make Rotator 节点上,将 返回值(Return Value) 引脚连接至SetRelativeRotation节点的 新旋转(New Rotation) 引脚。
-
编译 并 保存。
创建绑定盒体碰撞重叠事件
盒体组件需要拥有在Actor进入或离开碰撞边界时做出反应的能力。
-
导航至BP_DoorActor的组件(Components)选项卡,选择盒体组件。
-
从细节面板中,向下滚动到事件类别,点击 在组件开始重叠时(On Component Begin Overlap) 事件旁的 + 图标。
-
在 On Component Begin Overlap(Box) 节点上,拖移执行引脚,将其连接至DoorTimelineComponent节点的播放(Play)引脚。
-
导航至BP_DoorActor的组件(Components)选项卡,选择盒体组件。然后,在细节面板向下滚动到事件类别,点击 在组件结束重叠时(On Component End Overlap) 事件旁的 + 图标。
-
在 On Component End Overlap(Box) 节点上,拖移执行引脚,将其连接至TimelineComponent节点的 反向(Reverse) 引脚。
-
编译 并 保存。
将Actor放到关卡中
-
从内容浏览器中,选择你的BP_DoorActor并将其拖动到视口中。
-
按PIE
可以使用WASD键控制我们的旁观者Pawn。导航至DoorActor的碰撞边界时,可以在门打开时观察时间轴播放。退出边界时,可以观察到时间轴反向播放。
完成后的蓝图
BP_DoorActor

使用示例C++ 时间轴 来创建基于距离的经典开门。

创建门Actor
-
基于 空白(Blank) 模板新建一个 C++ 项目,启用 初学者内容包(Starter Content) ,将项目命名为 TimelineDoorActor 。
点击查看大图。
-
找到 内容浏览器(Content Browser) ,点击 C++ Classes 文件夹,然后点击 添加(+)(Add [+]) 按钮并选择 新建C++类(New C++ Class) 。
点击查看大图。
-
选择 Actor 作为 父类(Parent Class) 。
点击查看大图。
-
将创建的Actor命名为 DoorActor 。
点击查看大图。
-
创建新Actor时, Visual Studio 会自动打开
DoorActor.h
和DoorActor.cpp
文件。找到DoorActor.h
文件,并声明以下内容:DoorActor.h
#include "Components/TimelineComponent.h"
-
接下来,在
DoorActor
类定义中添加以下代码:DoorActor.h
protected: //用于表示门资产的网格体组件 UPROPERTY(VisibleAnywhere, BlueprintReadWrite) UStaticMeshComponent* DoorFrame; UPROPERTY(VisibleAnywhere, BlueprintReadWrite) UStaticMeshComponent* Door; //用于对门网格体进行动画处理的时间轴组件 UPROPERTY(VisibleAnywhere, BlueprintReadWrite) UTimelineComponent* DoorTimelineComp; //将用作我们的距离体积的盒体组件。 UPROPERTY(EditAnywhere, BlueprintReadWrite) class UBoxComponent* DoorProxVolume;
-
找到
DoorActor.cpp
。需要包括以下类库,方可利用你的盒体组件。DoorActor.cpp
#include "Components/BoxComponent.h"
-
在你的 ADoorActor::ADoorActor 的构造函数中声明以下内容:
DoorActor.cpp
// 设置默认值 ADoorActor::ADoorActor() { // 将此Actor设置为每帧调用更新函数()。 如果不需要此特性,可以关闭以提升性能。 PrimaryActorTick.bCanEverTick = true; //创建我们的默认组件 DoorFrame = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorFrameMesh")); Door = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorMesh")); DoorTimelineComp = CreateDefaultSubobject<UTimelineComponent>(TEXT("DoorTimelineComp")); DoorProxVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("DoorProximityVolume")); //设置我们的附件 DoorFrame->SetupAttachment(RootComponent); Door->AttachToComponent(DoorFrame, FAttachmentTransformRules::KeepRelativeTransform); DoorProxVolume->AttachToComponent(DoorFrame, FAttachmentTransformRules::KeepRelativeTransform); }
注意:我们将门的相对变换保留为附件规则,以便稍后使用门Actor的自定义方法来操作它。 详情请参阅FAttachmentTransformRules。
-
编译你的代码。
设置门静态网格体
你需要设置 静态网格体(Static Mesh) 资产,直观地表示你的DoorFrame和Door静态网格体组件。
-
在 内容浏览器(Content Browser) 中,找到你的 C++ Classes 文件夹。
-
右键点击你的 DoorActor 类,选择 基于DoorActor创建蓝图类(Create Blueprint Class based on DoorActor) 。
-
将你的蓝图Actor命名为 Bp_DoorActor 并将其放入相应的文件夹。
点击查看大图。
-
从 组件(Components) 选项卡中选择 DoorFrame 静态网格体组件。
-
找到 细节(Details) 面板,将 静态网格体(Static Mesh) 更改为 SM_DoorFrame 。
-
找到 组件(Components) 选项卡,选择 DoorMesh 组件。
-
在 细节(Details) 面板中,将 静态网格体(Static Mesh) 更改为 SM_Door 。
-
然后找到 变换(Transform) 类别,将 Y位置(Y Location) 值更改为 45.0 。
-
点击 编译(Compile) 和 保存(Save) 按钮。
创建UCurveFloat和时间轴事件轨道
时间轴(Timeline)组件需要时间轴曲线。每个曲线都可以包含多个键,用于定义时间和值。曲线内插这些键,以计算时间轴中任何点的值。
此例中,我们将使用UCurveFloat。
-
找到
DoorActor.h
中的ADoorActor
类定义,并声明以下变量:DoorActor.h
public: // 用于保留曲线资产的变量 UPROPERTY(EditAnywhere) UCurveFloat* DoorTimelineFloatCurve; private: //用于处理我们的更新轨道事件的浮点轨道签名 FOnTimelineFloat UpdateFunctionFloat; //用于使用时间轴图表更新门相对位置的函数 UFUNCTION() void UpdateTimelineComp(float Output);
-
找到
DoorActor.cpp
并实现UpdateTimelineComp
方法:DoorActor.cpp
void ADoorActor::UpdateTimelineComp(float Output) { // 基于时间轴曲线的输出创建并设置门的新相对位置 FRotator DoorNewRotation = FRotator(0.0f, Output, 0.f); Door->SetRelativeRotation(DoorNewRotation); }
-
然后,在
BeginPlay
方法中,添加以下代码:DoorActor.cpp
//将浮点轨道绑定到UpdateTimelineComp函数的输出 UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp); //如果有浮点曲线,将其图表绑定到我们的更新函数 if (DoorTimelineFloatCurve) { DoorTimelineComp->AddInterpFloat(DoorTimelineFloatCurve, UpdateFunctionFloat); }
-
编译你的代码。
阶段性代码
DoorActor.h
// 版权所有1998-2022 Epic Games, Inc.保留所有权利。
#pragma once
#include "Components/TimelineComponent.h"
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "DoorActor.generated.h"
UCLASS()
class TIMELINEDOORACTOR_API ADoorActor : public AActor
{
GENERATED_BODY()
public:
// 为此Actor的属性设置默认值
ADoorActor();
protected:
// 当游戏开始或重生(Spawn)时调用
virtual void BeginPlay() override;
public:
// 每一帧都调用
virtual void Tick(float DeltaTime) override;
protected:
//用于表示门资产的网格体组件
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* DoorFrame;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* Door;
//用于对门网格体进行动画处理的时间轴组件
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UTimelineComponent* DoorTimelineComp;
//将用作我们的距离体积的盒体组件。
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UBoxComponent* DoorProxVolume;
public:
// 用于保留曲线资产的变量
UPROPERTY(EditAnywhere)
UCurveFloat* DoorTimelineFloatCurve;
private:
//用于处理我们的更新轨道事件的浮点轨道签名
FOnTimelineFloat UpdateFunctionFloat;
//用于使用时间轴图表更新门相对位置的函数
UFUNCTION()
void UpdateTimelineComp(float Output);
}
DoorActor.cpp
//版权所有 1998-2022 Epic Games, Inc。保留所有权利。
#include "DoorActor.h"
#include "Components/BoxComponent.h"
// 设置默认值
ADoorActor::ADoorActor()
{
// 将此Actor设置为每帧调用更新函数()。 如果不需要此特性,可以关闭以提升性能。
PrimaryActorTick.bCanEverTick = true;
//创建我们的默认组件
DoorFrame = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorFrameMesh"));
Door = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorMesh"));
DoorTimelineComp = CreateDefaultSubobject<UTimelineComponent>(TEXT("DoorTimelineComp"));
DoorProxVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("DoorProximityVolume"));
//设置我们的附件
DoorFrame->SetupAttachment(RootComponent);
Door->AttachToComponent(DoorFrame, FAttachmentTransformRules::KeepRelativeTransform);
DoorProxVolume->AttachToComponent(DoorFrame, FAttachmentTransformRules::KeepRelativeTransform);
}
// 当游戏开始或重生(Spawn)时调用
void ADoorActor::BeginPlay()
{
Super::BeginPlay();
//将浮点轨道绑定到UpdateTimelineComp函数的输出
UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp);
//如果有浮点曲线,将其图表绑定到我们的更新函数
if (DoorTimelineFloatCurve)
{
DoorTimelineComp->AddInterpFloat(DoorTimelineFloatCurve, UpdateFunctionFloat);
}
}
// 每一帧都调用
void ADoorActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ADoorActor::UpdateTimelineComp(float Output)
{
// 基于时间轴曲线的输出创建并设置门的新相对位置
FRotator DoorNewRotation = FRotator(0.0f, Output, 0.f);
Door->SetRelativeRotation(DoorNewRotation);
}
创建并绑定盒体碰撞重叠事件
盒体组件需要拥有在Actor进入或离开碰撞边界时做出反应的能力。
-
找到你的
DoorActor.h
文件的类定义,并声明以下内容:DoorActor.h
// DoorProxVolume的开始和结束重叠事件 UFUNCTION() void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); UFUNCTION() void OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
-
接下来,找到
DoorActor.cpp
文件,以实现OnOverlapBegin
和OnOverlapEnd
类方法:DoorActor.cpp
void ADoorActor::OnOverlapBegin(UPrimitiveComponent * OverlappedComp, AActor * OtherActor, UPrimitiveComponent * OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult) { DoorTimelineComp->Play(); } void ADoorActor::OnOverlapEnd(UPrimitiveComponent * OverlappedComp, AActor * OtherActor, UPrimitiveComponent * OtherComp, int32 OtherBodyIndex) { DoorTimelineComp->Reverse(); }
-
在
BeginPlay
方法中绑定重叠函数,如下所示:DoorActor.cpp
void ADoorActor::BeginPlay() { Super::BeginPlay(); //将浮点轨道绑定到UpdateTimelineComp函数的输出 UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp); //如果有浮点曲线,将其图表绑定到我们的更新函数 if (DoorTimelineFloatCurve) { DoorTimelineComp->AddInterpFloat(DoorTimelineFloatCurve, UpdateFunctionFloat); } //将我们的距离盒体组件绑定到我们的重叠函数 DoorProxVolume->OnComponentBeginOverlap.AddDynamic(this, &ADoorActor::OnOverlapBegin); DoorProxVolume->OnComponentEndOverlap.AddDynamic(this, &ADoorActor::OnOverlapEnd); }
-
编译你的代码。
在虚幻编辑器中创建曲线资产
必须在 虚幻编辑器(Unreal Editor) 中创建 曲线资产(Curve Asset) ,以将其指定给你的时间轴Actor蓝图。
-
找到 内容浏览器(Content Browser) ,选择 添加(+)(Add [+])> 杂项(Miscellaneous)> 曲线(Curve) 。
-
选择 CurveFloat 并将资产命名为 DoorCurveFloat 。
-
双击创建的 DoorCurveFloat ,打开 时间轴编辑器(Timeline Editor) 。
-
在 图表(Graph) 上点击右键,然后选择 添加键(Add Key) ,为浮动曲线添加两个键。将第一个键的时间值调整为 (0, 0) 。将第二个键的时间值调整为 (4, 90) 。
点击查看大图。
有关编辑 时间轴(Timeline) 曲线的更多信息,请参阅键和曲线。
-
按住 Shift 键并点击以选中这两个键,在 图表(Graph) 上点击右键,将它们设置为 自动(Auto) 插值。
点击查看大图。
-
现在你的曲线内容应如下所示。保存你的 DoorCuveFloat 并关闭 时间轴编辑器(Timeline Editor) 。
点击查看大图。
-
打开你的 Bp_DoorActor ,并从 组件(Components) 选项卡中选择 Bp_DoorActor 。
-
找到 细节(Details) 面板,并从 门操作(Door Action) 分段的 门时间轴浮点曲线(Door Timeline Float Curve) 下拉菜单中选择 DoorCurveFloat 。
-
找到 内容浏览器(Content Browser) ,并将 Bp_DoorActor 放入 关卡(Level) 。
-
编译并保存,然后按PIE。
你可以使用WASD键进行输入,以控制旁观者Pawn。找到你的DoorActor的碰撞边界时,你可以观察到时间轴播放,而在退出边界时,可以观察到时间轴反向播放。
已完成代码
DoorActor.h
// 版权所有1998-2022 Epic Games, Inc.保留所有权利。
#pragma once
#include "Components/TimelineComponent.h"
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "DoorActor.generated.h"
UCLASS()
class TIMELINEDOORACTOR_API ADoorActor : public AActor
{
GENERATED_BODY()
public:
// 为此Actor的属性设置默认值
ADoorActor();
protected:
// 当游戏开始或重生(Spawn)时调用
virtual void BeginPlay() override;
public:
// 每一帧都调用
virtual void Tick(float DeltaTime) override;
protected:
//用于表示门资产的网格体组件
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* DoorFrame;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* Door;
//用于对门网格体进行动画处理的时间轴组件
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UTimelineComponent* DoorTimelineComp;
//将用作我们的距离体积的盒体组件。
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UBoxComponent* DoorProxVolume;
public:
// 用于保留曲线资产的变量
UPROPERTY(EditAnywhere)
UCurveFloat* DoorTimelineFloatCurve;
private:
//用于处理我们的更新轨道事件的浮点轨道签名
FOnTimelineFloat UpdateFunctionFloat;
//用于使用时间轴图表更新门相对位置的函数
UFUNCTION()
void UpdateTimelineComp(float Output);
// DoorProxVolume的开始和结束重叠事件
UFUNCTION()
void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
};
DoorActor.cpp
// 版权所有1998-2022 Epic Games, Inc.保留所有权利。
#include "DoorActor.h"
#include "Components/BoxComponent.h"
// 设置默认值
ADoorActor::ADoorActor()
{
// 将此Actor设置为每帧调用更新函数()。 如果不需要此特性,可以关闭以提升性能。
PrimaryActorTick.bCanEverTick = true;
//创建我们的默认组件
DoorFrame = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorFrameMesh"));
Door = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorMesh"));
DoorTimelineComp = CreateDefaultSubobject<UTimelineComponent>(TEXT("DoorTimelineComp"));
DoorProxVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("DoorProximityVolume"));
//设置我们的附件
DoorFrame->SetupAttachment(RootComponent);
Door->AttachToComponent(DoorFrame, FAttachmentTransformRules::KeepRelativeTransform);
DoorProxVolume->AttachToComponent(DoorFrame, FAttachmentTransformRules::KeepRelativeTransform);
}
// 当游戏开始或重生(Spawn)时调用
void ADoorActor::BeginPlay()
{
Super::BeginPlay();
//将浮点轨道绑定到UpdateTimelineComp函数的输出
UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp);
//如果有浮点曲线,将其图表绑定到我们的更新函数
if (DoorTimelineFloatCurve)
{
DoorTimelineComp->AddInterpFloat(DoorTimelineFloatCurve, UpdateFunctionFloat);
}
//将我们的距离盒体组件绑定到我们的重叠函数
DoorProxVolume->OnComponentBeginOverlap.AddDynamic(this, &ADoorActor::OnOverlapBegin);
DoorProxVolume->OnComponentEndOverlap.AddDynamic(this, &ADoorActor::OnOverlapEnd);
}
// 每一帧都调用
void ADoorActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ADoorActor::UpdateTimelineComp(float Output)
{
// 基于时间轴曲线的输出创建并设置门的新相对位置
FRotator DoorNewRotation = FRotator(0.0f, Output, 0.f);
Door->SetRelativeRotation(DoorNewRotation);
}
void ADoorActor::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
DoorTimelineComp->Play();
}
void ADoorActor::OnOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
DoorTimelineComp->Reverse();
}