3
2

More than 1 year has passed since last update.

UE4 タイムラインについてのメモ

Posted at

概要

UnrealEngine のタイムラインについてのメモ書きです。

環境

Windows10
Visual Studio 2017
UnrealEngine 4.26

参考

以下を参考にさせて頂きました、ありがとうございます。

公式 : 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 いずれかを選ぶ。

Create_Curve.png

右クリックでキーを設定してカーブを作成します。
https://docs.unrealengine.com/4.26/ja/Basics/UI/CurveEditor/

floatのカーブ例:
CurveData.png

BPでの実装例

右クリックで「タイムラインを追加する」を選び、タイムラインコンポーネントを追加します。
create_timelineBP.png

Updateピンで更新データが、Finishedピンでタイムライン終了時の処理が呼ばれます。
TimelineBP.png

タイムラインノードをダブルクリックするとカーブデータビューに切り替わります。ここで直接カーブデータを入力するか、外部カーブデータを指定します。
Vectorカーブ例:
TimeLineCurve.png

C++での実装例1(タイムラインコンポーネントを使用)

タイムラインコンポーネントを使った例。
コンポーネントを作成してカーブデータと更新メソッド、終了メソッドを定義します。
以下コード例。

MyActor.h
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();
};
MyActor.cpp
#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 に切り替えて時間を入れる。

以下コード例

MyActor.h
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();
};
MyActor.cpp
#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++で作成するには以下のようになります。
以下コード例:

Floatカーブ
    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);
    }

Vectorカーブ
    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);
    }

アセットにするまでもない場合は使ってもいいかもです。

まとめ

タイムラインコンポーネントを乱発で使うと処理負荷が高そうなので使いどころに注意が要りそうです。単純な計算式では表現できないところだけで使うべきかなと思われます。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2