このチュートリアルでは、(Basics/Packs) で利用できるリソースを使って、Timeline ブループリントで接近すると開くドアの設定方法を紹介します。
Door アクタを作成する
- Blueprint project based on ブランク テンプレートで スターター コンテンツ を有効して新しい ブループリント プロジェクトを作成して「TimelineDoorActor」と名前を付けます。
-
コンテンツ ブラウザ へ移動して、 [Add (+) (追加)] ボタンをクリックして新しいブループリントを作成します。
-
[Actor (アクタ)] を親クラスとして選択し、ブループリントに「BP_DoorActor」という名前を付けます。
-
コンテンツ ブラウザ から BP_DoorActor アクタをダブルクリックして ブループリント エディタ で開いて Class Defaults を開きます。
-
次に、[Components] タブから [Add (追加)] ボタンをクリックし [Static Mesh] を選択して Static Mesh Component を追加します。
-
StaticMesh を右クリックし、[Rename (名前を変更)] を選択して DoorFrame に名前を変更します。
-
次に、[Components] タブから [Add (追加)] ボタンをクリックし [Static Mesh] を選択して Static Mesh Component を追加します。(Repeating step 3)
-
StaticMesh を右クリックし、[Rename (名前を変更)] を選択して Door に名前を変更します。
-
[Components (コンポーネント)] タブ [Add (追加)] ボタンをクリックし、ドロップダウン メニューから [Box Collision] を選択して「Box」に名前を変更します。
-
ブループリント エディタ で イベント グラフ を開いて グラフ を右クリックし、コンテキスト メニューから [Add Timeline (タイムラインを追加する)] を検索して追加します。タイムラインに DoorTimelineComponent と名前をつけます。
Door Static Mesh を設定する
次に、[Components] タブのアタッチメント階層を設定する必要があります。
DoorFrame スタティックメッシュ コンポーネントと Door スタティックメッシュ コンポーネントを視覚的に表示するスタティックメッシュ アセットも設定する必要があります。
-
BP_DoorActor の [Component] タブから DoorFrame スタティックメッシュを選択し、それを DefaultSceneRoot コンポーネント にドラッグして新しい ルート コンポーネント にします。
-
[Components] タブで DoorFrame スタティックメッシュを選択し、[Details] パネルでスタティックメッシュを SM_DoorFrame に変更します。
-
次に、[Components (コンポーネント)] タブから Door コンポーネントを選択します。
-
[Details (詳細)] パネルに移動してスタティックメッシュ を「SM_Door」に変更します。
- Transform カテゴリに移動し、Y Location 値を 45.0 に変更します。
-
[Save (保存する)] と [Compile (コンパイルする)] をクリックしてこれらの変更を Bp_DoorActor に保存します。
Timeline Float Track を作成する
Timeline Component では移動アニメーションを記述するために Timeline Curve を必要とします。それぞれのカーブには、時間と値を定義する複数のキーが含まれています。カーブはこれらのキーを補間して、タイムライン中の任意のポイントの値を計算します。
- まず、イベントグラフ の DoorTimelineComponent をダブルクリックして Timeline エディタ を開いて、Track > Add Float Track をクリックして新規カーブをトラックに追加します。
- カーブに「DoorRotationZ」という名前を付けます。
- 右クリックして Float カーブ トラックにキーを 2 つ追加します。値は (0, 0) ともう 1 つは (5, 90) にします。
- Shift キーを押して両方のキーを選択し、[Key Interpolation (キー補間)] ドロップダウン メニューから [Auto (自動)] 補間を選択します。
- すべてを調節すると、float トラックは以下のようになります。Float トラックを保存します。
イベント トラック ロジックを更新する
次に、Door スタティックメッシュを回転させるための更新ロジックを作成する必要があります。
- BP_DoorActor の [Components] タブに移動し、Door スタティックメッシュを イベントグラフ にドラッグします。
- Door ピンを引き出し、アクション コンテキスト メニューから SetRelativeRotation ノードを選択します。
- イベント グラフ を右クリックして、アクション コンテキスト メニューから Make Rotator ノードを検索して追加します。
-
DoorTimelineComponent ノードから Door Rotation Z float ピンを引き出して Make Rotator ノードの Z(Yaw) ピンにつなぎます。
-
DoorTimelineComponent ノードから Update ピン を引き出して SetRelativeRotation ノードの入力 実行 ピンにつなぎます。Make Rotator ノードの Return Value ピンを SetRelativeRotation ノードの New Rotation ピンに接続します。ブループリントは次のようになります。
-
[Compile (コンパイル)] と [Save (保存)] ボタンを順にクリックします。
Binding Box Collision Overlap イベントを作成する
アクタがコリジョン領域に出入りするときに Box コンポーネントが反応する機能が必要です。
-
BP_DoorActor の [Components] タブで Box コンポーネントから Box コンポーネントを選択します。
-
[Details (詳細)] パネルで [Events (イベント)] カテゴリまでスクロールして、On Component Begin Overlap イベントの隣にある [+] アイコンをクリックします。
-
BP_DoorActor の [Components] タブで Box コンポーネントを選択します。
-
[Details] パネルの Events カテゴリを下にスクロールし、On Component End Overlap イベントの横にある [+] アイコンをクリックします。
-
On Component Begin Overlap(Box) ノードの 実行ピンを DoorTimelineComponent ノードの Play ピンにつなぎます。On Component Begin Overlap(Box) ノードの 実行ピンを DoorTimelineComponent ノードの Reverse ピンにつなぎます。ブループリント スクリプトは次のようになります。
-
[Compile (コンパイル)] と [Save (保存)] ボタンを順にクリックします。
アクタをレベルに配置する
- コンテンツ ブラウザ で BP_DoorActor を選択して レベル にドラッグします。[Detailed] パネルで Box コンポーネントを選択して、Transform セクションで [Location] と [Scale] を以下のように調整します。
-
[Play (PIE)] ボタンをクリックします。
完成したブループリント
BP_DoorActor
C++ Timeline を使って接近すると開くドアの設定方法の例を紹介します。
Door アクタを作成する
- ブランク テンプレートで スターター コンテンツ を有効にして新しい C++ プロジェクトを作成して「TimelineDoorActor」と名前を付けます。
- コンテンツ ブラウザ で「C++ Classes」フォルダをクリックし、[Add (+) (追加)] ボタンをクリックして [New C++ Class (新規 C++ クラス)] を選択します。
- アクタ を 親クラス として選択します。
- 作成したアクタに「DoorActor」という名前を付けます。
- 新しいアクタを作成すると、Visual Studio では自動的に「
DoorActor.h
」と「DoorActor.cpp
」ファイルが開かれます。DoorActor.h
ファイルに移動して次のように宣言します。
DoorActor.h
#include "Components/TimelineComponent.h"
- 次に、
DoorActor
クラスの定義に次のコードを追加します。
DoorActor.h
protected:
//ドア アセットを表現するための MeshComponent
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* DoorFrame;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* Door;
//ドア メッシュをアニメートするための TimelineComponent
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UTimelineComponent* DoorTimelineComp;
//近接ボリュームとして使用する BoxComponent
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UBoxComponent* DoorProxVolume;
- 「
DoorActor.cpp
」に移動します。以下のクラス ライブラリをインクルードして Box コンポーネントを使用します。
DoorActor.cpp
#include "Components/BoxComponent.h"
ADoorActor::ADoorActor
のコンストラクタで、次のように宣言します。
DoorActor.cpp
// デフォルト値を設定します。
ADoorActor::ADoorActor()
{
// 各フレームでこのアクタが Tick() を呼び出すよう設定します。必要ない場合は、パフォーマンス向上のためにこれをオフにすることができます。
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);
}
注:後で Door アクタのカスタム メソッドを使って操作するために、ドアの相対トランスフォームをアタッチメント ルールとして保持します。 詳細については、「FAttachmentTransformRules」を参照してください。
- コードをコンパイルします。
Door Static Mesh を設定する
DoorFrame スタティックメッシュ コンポーネントと Door スタティックメッシュ コンポーネントを視覚的に表示する スタティックメッシュ アセットも設定する必要があります。
-
コンテンツ ブラウザ から C++ Classes フォルダ に移動します。
-
DoorActor クラスを右クリックして [Create Blueprint Class based on DoorActor (DoorActor に基づいてブループリント クラスを作成する)] を選択します。
-
ブループリント アクタに「Bp_DoorActor」という名前を付け、適切なフォルダ内に配置します。
-
[Components (コンポーネント)] タブで、DoorFrame スタティックメッシュ コンポーネントを選択します。
-
[Details (詳細)] パネル に移動し、スタティックメッシュ を SM_DoorFrame に変更します。
-
[Components] タブに移動し、DoorMesh コンポーネントを選択します。
-
[Details] パネルで スタティックメッシュ を SM_Door に変更します。
-
Transform カテゴリに移動し、Y Location 値を 45.0 に変更します。
-
[Compile (コンパイル)] ボタンと [Save (保存)] ボタンを順にクリックします。
UCurveFloat トラックと Timeline イベント トラックを作成する
Timeline Component では、Timeline Curve を必要とします。各カーブには時間と値を定義する複数のキーを含むことができます。カーブはこれらのキーを補間して、タイムライン中の任意のポイントの値を計算します。
この例では、UCurveFloat を使用します。
DoorActor.h
のADoorActor
クラス定義へ移動し、次の変数を宣言します。
DoorActor.h
public:
// カーブ アセットを保持するための変数
UPROPERTY(EditAnywhere)
UCurveFloat* DoorTimelineFloatCurve;
private:
//トラック イベントを更新するための Float トラック シグネチャ
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 関数の出力に Float トラックをバインドします。
UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp);
//Float カーブがある場合は、そのグラフを更新関数にバインドします。
if (DoorTimelineFloatCurve)
{
DoorTimelineComp->AddInterpFloat(DoorTimelineFloatCurve, UpdateFunctionFloat);
}
- コードをコンパイルします。
作成中のコード
DoorActor.h
// Copyright 1998-2022 Epic Games, Inc. All Rights Reserved.
#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:
// このアクタのプロパティのデフォルト値を設定します。
ADoorActor();
protected:
// ゲームの開始時またはスポーン時に呼び出します。
virtual void BeginPlay() override;
public:
// フレームごとに呼び出します。
virtual void Tick(float DeltaTime) override;
protected:
//ドア アセットを表現するための MeshComponent
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* DoorFrame;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* Door;
//ドア メッシュをアニメートするための TimelineComponent
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UTimelineComponent* DoorTimelineComp;
//近接ボリュームとして使用する BoxComponent
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UBoxComponent* DoorProxVolume;
public:
// カーブ アセットを保持するための変数
UPROPERTY(EditAnywhere)
UCurveFloat* DoorTimelineFloatCurve;
private:
//トラック イベントを更新するための Float トラック シグネチャ
FOnTimelineFloat UpdateFunctionFloat;
//タイムライン グラフに対するドアの相対位置を更新する関数
UFUNCTION()
void UpdateTimelineComp(float Output);
}
DoorActor.cpp
//Copyright 1998-2022 Epic Games, Inc. All Rights Reserved.
#include "DoorActor.h"
#include "Components/BoxComponent.h"
// デフォルト値を設定します。
ADoorActor::ADoorActor()
{
// 各フレームでこのアクタが Tick() を呼び出すよう設定します。必要ない場合は、パフォーマンス向上のためにこれをオフにすることができます。
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);
}
// ゲームの開始時またはスポーン時に呼び出します。
void ADoorActor::BeginPlay()
{
Super::BeginPlay();
//UpdateTimelineComp 関数の出力に Float トラックをバインドします。
UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp);
//Float カーブがある場合は、そのグラフを更新関数にバインドします。
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);
}
Collision Overlap イベントを作成してバインドする
アクタがコリジョン領域に出入りするときに Box コンポーネントが反応する機能が必要です。
- 「
DoorActor.h
」ファイルのクラス定義に移動し、次のように宣言します。
DoorActor.h
// DoorProxVolume の Begin および End Overlap イベント
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 関数の出力に Float トラックをバインドします。
UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp);
//Float カーブがある場合は、そのグラフを更新関数にバインドします。
if (DoorTimelineFloatCurve)
{
DoorTimelineComp->AddInterpFloat(DoorTimelineFloatCurve, UpdateFunctionFloat);
}
//Proximity Box コンポーネントをオーバーラップ関数にバインドします。
DoorProxVolume->OnComponentBeginOverlap.AddDynamic(this, &ADoorActor::OnOverlapBegin);
DoorProxVolume->OnComponentEndOverlap.AddDynamic(this, &ADoorActor::OnOverlapEnd);
}
- コードをコンパイルします。
Unreal Editor でカーブ アセットを作成する
Timeline Actor ブループリントに割り当てるために Unreal Editor で カーブ アセット を作成する必要があります。
-
コンテンツ ブラウザ に移動し、[+Add (+追加)] > [Miscellaneous (その他)] > [Curve (カーブ)] を選択します。
-
[CurveFloat] を選択してアセットの名前を「DoorCurveFloat」にします。
-
作成された DoorCurveFloat をダブルクリックして タイムライン エディタ を開きます。
-
グラフ をクリックして [Add Key (キーを追加)] を選択して、2 つのキーを Float カーブに追加します。1 つめのキーの時間値を (0, 0) に調節します。2 つめのキーの時間値を (4, 90) に調節します。
Timeline カーブの編集に関する詳細は、「キーとカーブ」を参照してください。
- Shift キーを押しながら 2 つのキーを選択し、グラフ を右クリックして、それらに Auto 補間を設定します。
- カーブは次のようになります。DoorCuveFloat を保存して、タイムライン エディタ を終了します。
-
Bp_DoorActor を開いて [Components] タブで Bp_DoorActor を選択します。
-
[Details] パネルに移動し、[Door Action (ドア アクション)] セクションの [Door Timeline Float Curve (ドア タイムライン フロート カーブ)] ドロップダウン メニューから DoorCurveFloat を選択します。
-
コンテンツ ブラウザ に移動して、レベル に Bp_DoorActor を配置します。
-
コンパイルして保存し、PIE を押します。
完成コード
DoorActor.h
// Copyright 1998-2022 Epic Games, Inc. All Rights Reserved.
#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:
// このアクタのプロパティのデフォルト値を設定します。
ADoorActor();
protected:
// ゲームの開始時またはスポーン時に呼び出します。
virtual void BeginPlay() override;
public:
// フレームごとに呼び出します。
virtual void Tick(float DeltaTime) override;
protected:
//ドア アセットを表現するための MeshComponent
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* DoorFrame;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* Door;
//ドア メッシュをアニメートするための TimelineComponent
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UTimelineComponent* DoorTimelineComp;
//近接ボリュームとして使用する BoxComponent
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UBoxComponent* DoorProxVolume;
public:
// カーブ アセットを保持するための変数
UPROPERTY(EditAnywhere)
UCurveFloat* DoorTimelineFloatCurve;
private:
//トラック イベントを更新するための Float トラック シグネチャ
FOnTimelineFloat UpdateFunctionFloat;
//タイムライン グラフに対するドアの相対位置を更新する関数
UFUNCTION()
void UpdateTimelineComp(float Output);
// DoorProxVolume の Begin および End Overlap イベント
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
// Copyright 1998-2022 Epic Games, Inc. All Rights Reserved.
#include "DoorActor.h"
#include "Components/BoxComponent.h"
// デフォルト値を設定します。
ADoorActor::ADoorActor()
{
// 各フレームでこのアクタが Tick() を呼び出すよう設定します。必要ない場合は、パフォーマンス向上のためにこれをオフにすることができます。
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);
}
// ゲームの開始時またはスポーン時に呼び出します。
void ADoorActor::BeginPlay()
{
Super::BeginPlay();
//UpdateTimelineComp 関数の出力に Float トラックをバインドします。
UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp);
//Float カーブがある場合は、そのグラフを更新関数にバインドします。
if (DoorTimelineFloatCurve)
{
DoorTimelineComp->AddInterpFloat(DoorTimelineFloatCurve, UpdateFunctionFloat);
}
//Proximity Box コンポーネントをオーバーラップ関数にバインドします。
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();
}