概要
UnrealEngine のタイムラインについてのメモ書きです。
環境
Windows10
Visual Studio 2017
UnrealEngine 4.26
参考
以下を参考にさせて頂きました、ありがとうございます。
[公式 : FTimeline]
(https://docs.unrealengine.com/4.27/en-US/API/Runtime/Engine/Components/FTimeline/)
公式 : タイムラインパリティの概要
UnrealEngine4のタイムラインの使い方まとめ
関連コード
"Engine\Source\Runtime\Engine\Classes\Components\TimelineComponent.h"
"Engine\Source\Runtime\Engine\Private\Timeline.cpp"
"Engine\Source\Runtime\Engine\Classes\Curves\CurveBase.h"
タイムライン使用例
カーブの用意
コンテンツブラウザから右クリック
「その他」 -> 「カーブ」 -> 「カーブクラスを選択」でFloat
/LinearColor
/Vector
いずれかを選ぶ。
右クリックでキーを設定してカーブを作成します。
https://docs.unrealengine.com/4.26/ja/Basics/UI/CurveEditor/
BPでの実装例
右クリックで「タイムラインを追加する」を選び、タイムラインコンポーネントを追加します。
Update
ピンで更新データが、Finished
ピンでタイムライン終了時の処理が呼ばれます。
タイムラインノードをダブルクリックするとカーブデータビューに切り替わります。ここで直接カーブデータを入力するか、外部カーブデータを指定します。
Vectorカーブ例:
C++での実装例1(タイムラインコンポーネントを使用)
タイムラインコンポーネントを使った例。
コンポーネントを作成してカーブデータと更新メソッド、終了メソッドを定義します。
以下コード例。
UCLASS()
class TEST_API AMyActor : public AActor
{
GENERATED_BODY()
public:
// ..省略..
// タイムラインコンポーネント
class UTimelineComponent* MyTimelineComponent;
// カーブ
class UCurveFloat* MyCurve;
// タイマー
float Timer;
// タイムライン更新時に呼ばれる処理
UFUNCTION()
void TimelineStep(float _Value);
// タイムライン終了時に呼ばれる処理
UFUNCTION()
void TimelineFinished();
};
#include "Components/TimelineComponent.h"
AMyActor::AMyActor()
{
// ..省略..
// カーブアセットの取得
// カーブの種類によってクラスを選択(UCurveFloat / UCurveLinearColor / UCurveVector)
const ConstructorHelpers::FObjectFinder<UCurveFloat> _Find(TEXT("CurveFloat'/Game/TestCurve.TestCurve'"));
if( _Find.Succeeded()) {
MyCurve = _Find.Object;
}
MyTimelineComponent = CreateDefaultSubobject<UTimelineComponent>(TEXT("TimelineComponent0"));
if (MyTimelineComponent) {
// タイムライン更新時に呼び出されるメソッドの定義
FOnTimelineFloat _MyTimelineStepFunc;
_MyTimelineStepFunc.BindUFunction(this, TEXT("TimelineStep"));
MyTimelineComponent->AddInterpFloat(MyCurve, _MyTimelineStepFunc);
// タイムライン終了時に呼び出されるメソッドの定義
FOnTimelineEvent _MyTimelineFinishedFunc;
_MyTimelineFinishedFunc.BindUFunction(this, TEXT("TimelineFinished"));
MyTimelineComponent->SetTimelineFinishedFunc(_MyTimelineFinishedFunc);
}
}
void AMyActor::BeginPlay()
{
Super::BeginPlay();
Timer = 0.0f;
// タイムライン開始
if (MyTimelineComponent) {
MyTimelineComponent->PlayFromStart();
}
}
void AMyActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
Timer += DeltaTime;
}
// タイムライン更新時に呼ばれる処理
void AMyActor::TimelineStep(float _Value)
{
UE_LOG(LogTemp, Log, TEXT("Timeline(%.2f): Val=%.2f"), Timer, _Value);
}
// タイムライン終了時に呼ばれる処理
void AMyActor::TimelineFinished()
{
UE_LOG(LogTemp, Log, TEXT("TimelineFinished."));
}
C++での実装例2(タイムラインコンポーネントを未使用)
コンポーネントを使わずに内包している FTimeline
構造体を使った例。
カーブアセットを動作させて値を取得する場合、通常はカーブデータの最後のキーまで取得します。
特定時間まで取得する場合はモードをETimelineLengthMode::TL_TimelineLength
に切り替えて時間を入れる。
以下コード例
UCLASS()
class TEST_API AMyActor : public AActor
{
GENERATED_BODY()
public:
// ..省略..
// タイムライン
FTimeline* MyTimeline;
// カーブ
class UCurveFloat* MyCurve;
// タイマー
float Timer;
// タイムライン更新時に呼ばれる処理
UFUNCTION()
void TimelineStep(float _Value);
// タイムライン終了時に呼ばれる処理
UFUNCTION()
void TimelineFinished();
};
#include "Components/TimelineComponent.h"
AMyActor::AMyActor()
{
// ..省略..
// タイムライン初期化
MyTimeline = new FTimeline();
// ##タイムライン時間を指定したい場合は下のようにモードを設定して長さを指定する##
// タイムラインモード設定
// MyTimeline->SetTimelineLengthMode(ETimelineLengthMode::TL_TimelineLength);
// MyTimeline->SetTimelineLength(1.0f);
// カーブアセットの取得
// カーブの種類でクラスを指定(UCurveFloat / UCurveLinearColor / UCurveVector)
const ConstructorHelpers::FObjectFinder<UCurveFloat> _Find(TEXT("CurveFloat'/Game/TestCurve.TestCurve'"));
if( _Find.Succeeded()) {
MyCurve = _Find.Object;
}
// タイムライン更新時に呼び出されるメソッドの定義
FOnTimelineFloat _MyTimelineStepFunc;
_MyTimelineStepFunc.BindUFunction(this, TEXT("TimelineStep"));
MyTimeline->AddInterpFloat(MyCurve, _MyTimelineStepFunc);
// タイムライン終了時に呼び出されるメソッドの定義
FOnTimelineEvent _MyTimelineFinishedFunc;
_MyTimelineFinishedFunc.BindUFunction(this, TEXT("TimelineFinished"));
MyTimeline->SetTimelineFinishedFunc(_MyTimelineFinishedFunc);
}
void AMyActor::BeginPlay()
{
Super::BeginPlay();
Timer = 0.0f;
// タイムライン開始
if (MyTimeline != nullptr) {
MyTimeline->PlayFromStart();
}
}
void AMyActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
// タイムライン始末
if(MyTimeline){
delete MyTimeline;
MyTimeline = nullptr;
}
}
void AMyActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
Timer += DeltaTime;
// タイムライン実行処理
if( MyTimeline != nullptr && MyTimeline->IsPlaying() ){
MyTimeline->TickTimeline(DeltaTime);
}
}
// タイムライン更新時に呼ばれる処理
void AMyActor::TimelineStep(float _Value)
{
UE_LOG(LogTemp, Log, TEXT("Timeline(%.2f): Val=%.2f"), Timer, _Value);
}
// タイムライン終了時に呼ばれる処理
void AMyActor::TimelineFinished()
{
UE_LOG(LogTemp, Log, TEXT("TimelineFinished."));
}
C++でのカーブデータ作成について
アセットではなくC++で作成するには以下のようになります。
以下コード例:
UCurveFloat* MyCurve;
// オブジェクトフラグ
auto _ObjectFlag = EObjectFlags::RF_Public
| EObjectFlags::RF_Transactional
| EObjectFlags::RF_WasLoaded
| EObjectFlags::RF_LoadCompleted;
// Floatカーブオブジェクト生成
MyCurve = NewObject<UCurveFloat>(this, UCurveFloat::StaticClass(), TEXT("MyFloatCurve"), _ObjectFlag);
if(MyCurve){
MyCurve->FloatCurve.AddKey(0.0f, 0.0f); // Time, Value
MyCurve->FloatCurve.AddKey(1.0f, 0.6f);
MyCurve->FloatCurve.AddKey(2.0f, 3.0f);
}
UCurveVector* MyVectorCurve;
// Vectorカーブオブジェクト生成
MyVectorCurve = NewObject<UCurveVector>(this, UCurveVector::StaticClass(), TEXT("MyVectorCurve"), _ObjectFlag);
if(MyVectorCurve){
// X
MyVectorCurve->FloatCurves[0].AddKey(0.0f, 0.2f);
MyVectorCurve->FloatCurves[0].AddKey(1.0f, 0.8f);
// Y
MyVectorCurve->FloatCurves[1].AddKey(0.0f, 1.0f);
MyVectorCurve->FloatCurves[1].AddKey(1.0f, 0.9f);
// Z
MyVectorCurve->FloatCurves[2].AddKey(0.0f, 0.5f);
MyVectorCurve->FloatCurves[2].AddKey(1.0f, 0.7f);
}
アセットにするまでもない場合は使ってもいいかもです。
まとめ
タイムラインコンポーネントを乱発で使うと処理負荷が高そうなので使いどころに注意が要りそうです。単純な計算式では表現できないところだけで使うべきかなと思われます。