概要
インターフェースは、さまざまなアクタ クラスによって実装可能な共通の動作や関数を定義します。この通信方法は、さまざまなアクタ クラスに同じ種類の関数を実装する際に最適です。
例えば、プロジェクト内の複数アクタ クラスに共通のアクティベーション動作を実装する場合です。その場合のアクタ クラスには、ドアや窓、車などが考えられます。各アクタ クラスは異なるので、Open Interface 関数が呼び出されたときに別々の動作をします。
このような場合は、キャスティングよりもインターフェースのほうが適しています。なぜなら、同じ関数呼び出しをすべてのアクタ クラスに使用することができ、各アクタにそれぞれキャスティングする必要がないからです。
パフォーマンス上もインターフェースのほうがキャスティングよりも優れています。キャスティングの場合は、別のアクタにキャスティングするアクタをロードすると、続いて別のアクタもメモリにロードすることになるからです。慎重に扱わないと、1 つのアクタのローディングが複数アクタのローディングを引き起こしてメモリに格納される「カスケード ローディング効果」を招くおそれがあります。
この方法では、共通の関数にアクセスするために各アクタにインターフェースを実装する必要があります。インターフェース関数を呼び出すためにアクタへの参照も必要です。この通信方法では、作業アクタとターゲット アクタ間で 1 対 1 の関係を使用します。
目標
このクイック スタート ガイドでは、インターフェースを使用して 2 種類のアクタと通信するシンプルなインタラクション システムを作成する方法を学習します。
目的
-
Interact 関数を使ってインターフェースを作成する。
-
インタラクティブなランプ アクタとドア アクタを作成し、インターフェースを実装する。
-
近くにあるオブジェクトの Interact インターフェース関数を呼び出すように ThirdPersonCharacter ブループリントを変更します。
1 - 必要な設定
-
メニューの [New Project Categories (新規プロジェクトカテゴリ)] セクションにある [Games (ゲーム)] を選択して [Next (次へ)] をクリックします。
-
[Third Person (サードパーソン)] テンプレートを選択し、[Next (次へ)] をクリックします。
-
[Blueprint (ブループリント)] と [With Starter Content (スターター コンテンツあり)] オプションを選択し、[Create Project (プロジェクトの作成)] をクリックします。
このセクションの結果
新規のサードパーソン プロジェクトを作成し、インターフェースについて学ぶ準備ができました。
2 - インターフェースを作成する
-
コンテンツ ブラウザ 内を右クリックし、 [Blueprints (ブループリント)] > [Blueprint Interface (ブループリント インターフェース)] を選択します。インターフェースに「BPI_Interact」という名前を付けます。
レフィックスの BPI_ を付けて複数のブループリント インターフェースに共通する名前にします。
-
コンテンツ ブラウザ で BPI_Interact をダブルクリックして開きます。[Functions (関数)] 一覧の 1 番目にある関数に Interact という名前を付けます。
-
インターフェースを コンパイル して、 保存 します。
このセクションの結果
このセクションでは、インターフェースを作成して「Interact」という関数を追加しました。これで、このインターフェースを実装するアクタに、この関数を追加することができるようになりました。
3 - インタラクティブなランプを作成する
-
コンテンツ ブラウザ で [Starter Content (スターター コンテンツ)] > [Blueprints (ブループリント)] に移動します。Blueprint_CeilingLight を右クリックして [Duplicate (複製)] を選択します。このブループリントに「BP_Lamp 」という名前を付け、ゲーム フォルダに移動させます。
-
コンテンツ ブラウザ で BP_Lamp をダブルクリックして開きます。イベント グラフ 内で右クリックして、「Add Custom Event」を検索、選択します。イベントに「ToggleLight」という名前を付けます。
-
ToggleLight ノードからドラッグして、「Flip Flop」を検索、選択します。
-
Point Light 1 コンポーネントを イベント グラフ までドラッグし、参照ノードを作成します。Point Light 1 ノードからドラッグして、「Set Visibility」を検索、選択します。以下のように、Flip Flop ノードの A pin を Set Visibility ノードに接続します。
-
Point Light 1 ノードと Set Visibility ノードを接続し、それらを Flip Flop ノードの B pin につなぎます。New Visibility を「True」に設定します。
-
メニュー バーから [Class Settings (クラス設定)] をクリックし、[Details (詳細)] パネルに移動します。
-
[Interfaces (インターフェース)] セクションまでスクロールし、[Add (追加)] のドロップダウンをクリックし、「BP_Interact」を検索、選択します。ブループリントを コンパイル して、保存 します。
-
My Blueprint タブの [Interfaces (インターフェース)] セクションに移動します。Interact インターフェース関数を右クリックして Implement イベントを選択します。すると、イベント グラフに Event Interact** ノードが表示されます。
-
Event Interact ノードからドラッグして、 「ToggleLight」を検索、選択します。
-
ブループリントを コンパイル して、保存 します。
このセクションの結果
このセクションでは、Ceiling Lamp ブループリントを複製し、ライトのオンとオフを切り替えるカスタム イベントを追加しました。また、BPI_Interact インターフェースを実装し、ToggleLight イベントを実行する Interact 関数を設定しました。
4 - インタラクティブなドアを作成する
-
コンテンツ ブラウザ を右クリックして、[Create Basic Asset (基本アセットの作成)] セクション内の [Blueprint Class (ブループリント クラス)] をクリックします。
-
[Actor (アクタ)] クラスを親クラスとして選択し、ブループリントに「BP_Door」という名前を付けます。
-
コンテンツ ブラウザ で BP_Door をダブルクリックして開きます。次に、ブループリント エディタの [Components (コンポーネント)] パネルに移動して [Add Component (コンポーネントを追加)] ドロップダウンをクリックします。「Static Mesh」を検索、選択し、コンポーネントに「Frame」という名前を付けます。ブループリントに Static Mesh コンポーネントが追加されました。ブループリントに、Static Mesh コンポーネントが追加されます。
-
別の Static Mesh コンポーネントを追加し、「Door」という名前を付けます。
-
[Details (詳細)] パネルの Frame コンポーネントを選択し、[Static Mesh (スタティック メッシュ)]のドロップダウンをクリックし、「SM_DoorFrame」を検索し、選択します。
-
Door コンポーネントに対しても上の手順を繰り返し、SM_Door スタティック メッシュを追加します。
-
Door コンポーネントを選択した状態で、以下のように Y の位置を「45.0」に設定します。すると、ドアが枠にぴったり合っている状態で表示されるはずです。
-
イベント グラフ を右クリックして、「Add Custom Event」を検索、選択します。イベントに「OpenDoor」という名前を付けます。上の手順を繰り返して別のイベントを作成し、「CloseDoor」という名前を付けます。
-
OpenDoor イベント ノードからドラッグして、「Add Timeline」 を検索、選択します。タイムラインの名前を 「TM_Door」 にします。
-
CloseDoor イベントを TM_Door 上の Reverse 実行ピンに接続します。
-
TM_Door をダブルクリックして開きます。[Add Float Curve (Float カーブを追加)] ボタンをクリックして、Float トラックを追加し、「Alpha」という名前を付けます。[Length (長さ)] を「1.00」に設定します。
-
グラフを右クリックし、[Add key to CurveFloat_1 (CurveFloat_1 にキーを追加する)] を選択し、新しいポイントを追加します。[Time (時間)] と [Value (値)] を 「0.0」に設定します。
-
上の手順を繰り返して別のポイントを追加し、[Time (時間)] と [Value (値)] を 「1.0」に設定します。
-
イベント グラフ に戻って Door Static Mesh コンポーネントを イベント グラフ にドラッグし、ノードを作成します。Door ノードからドラッグして、「SetRelativeRotation」を検索、選択します。
-
TM_Door の Alpha ピンを Lerp ノードの Alpha ピンに接続します。最後に、B の値を以下のように「90.0」に設定します。
-
イベント グラフ を右クリックして、「Lerp Float」を検索、選択します。Lerp ノードの [Return Value (戻り値)] を SetRelativeRotation ノードの Yaw ピンに接続します。TM_Door の Alpha ピンを Lerp ノードの Alpha ピンに接続します。最後に、B の値を以下のように「90.0」に設定します。
-
TM_Door の Finished ピンからドラッグして、「Retriggerable Delay」を検索、選択します。ノードの値を「2.0」に設定します。
-
Retriggerable Delay ノードからドラッグして、「CloseDoor」を検索、選択します。
-
メニュー バーの [Class Settings (クラス設定)] をクリックします。
-
[Interfaces (インターフェース)] セクションの [Add (追加)] のドロップダウンをクリックし、「BP_Interact」を検索、選択します。
-
My Blueprint タブの [Interfaces (インターフェース)] セクションに移動します。Interact インターフェース関数を右クリックして Implement イベントを選択します。すると、イベント グラフに Event Interact** ノードが表示されます。
-
Event Interact ノードからドラッグして、「OpenDoor」を検索、選択します。
-
ブループリントを コンパイル して、保存 します。
このセクションの結果
このセクションでは、BPI_Interact インターフェースの Interact 関数が呼び出されたときにドアを開くインタラクティブなドア アクタを作成しました。
5 - プレイヤー ブループリントを変更する
-
レベル内にある ThirdPersonCharacter ブループリントを選択します。[World Outliner (ワールド アウトライナ)] に移動し、[Edit ThirdPersonCharacter] をクリックしてブループリント エディタを開きます。
-
次に、ブループリント エディタの [Components (コンポーネント)] パネルに移動して [Add Component (コンポーネントを追加)] ボタンをクリックします。Sphere Collision を検索して選択します。ブループリントに、Sphere Collision コンポーネントが追加されます。
-
Sphere Collision コンポーネントが選択された状態で[Details (詳細)] パネルに移動し、[Radius (半径)] の値を 200 に設定します。
-
Sphere Collision コンポーネントを右クリックして OnComponentBeginOverlap イベントを選択し、イベント グラフ に追加します。
-
On Component Begin Overlap ノードからドラッグし、「Interact (Message)」を検索して選択します。[BPI Interact (BPI インタラクト)] カテゴリの下から関数を選択します。
-
On Component Begin Overlap イベントの Other Actor ノードを Interact 関数の Target ピンに接続します。
-
ブループリントを コンパイル して、保存 します。
このセクションの結果
このセクションでは、Sphere コリジョン コンポーネントを、オーバーラップするアクタの検出を行う ThirdPersonCharacter ブループリントに追加しました。アクタが球形にオーバーラップすると、ブループリントがそのアクタの BPI_Interact インターフェースから Interact 関数を呼び出します。アクタに実装されているインターフェースがない場合は失敗します (メッセージは表示されません)。
6 - インタラクション システムをテストする
-
BP_Door アクタと BP_Lamp アクタをレベルにドラッグします。
-
[Play (プレイ)] を押して、各アクタに近づいたときのインタラクションを確認します。
このセクションの結果
このセクションでは、インタラクティブなドア アクタとランプ アクタでテストし、インタラクション システムが意図したとおりに動作することを確認しました。
このクイック スタート ガイドでは、各アクタに同一の Interface 関数を実装し、別々の関数を指定する方法を学習しました。また、インターフェースがさまざまなアクタの類似の関数を実装するのに適しており、キャスティングを必要としない理由も学びました。
次のステップ
インターフェースの使い方が分かったところで、今度は「アクタ通信」ドキュメント ページで参照されている他の通信手段を見てみましょう。
概要
インターフェースは、さまざまなアクタによって実装可能な共通の動作やメソッドを定義します。この通信方法は、特にさまざまなアクタ クラス ブループリント上で同じ関数を実装する際に役立ちます。
たとえば、プロジェクト内で複数のブループリント クラス (ドア、窓、車など) に共通の「開く」動作を実装するときにインターフェースを選択します。この例では、各アクタが異なるクラスであり、Open インターフェースが呼び出されたときはそれぞれ異なる反応をします。
パフォーマンス上もインターフェースのほうがキャスティングよりも優れています。キャスティングの場合は、別のアクタ クラス ブループリントにキャスティングするアクタ クラス ブループリントをロードすると、続いて別のブループリントもメモリにロードすることになるからです。慎重に扱わないと、1 つのブループリントのローディングが複数ブループリントのローディングを引き起こしてメモリに格納される「カスケード ローディング効果」を招くおそれがあります。
この方法では、共通の関数にアクセスするために各アクタ クラス ブループリントにインターフェースを実装する必要があります。
目標
このクイック スタート ガイドでは、インターフェースを使用して 2 種類のアクタ クラス ブループリントと通信するシンプルなインタラクション システムを作成する方法を学習します。
目的
-
Interact 関数を使ってインターフェースを作成する。
-
インタラクティブなランプとドアのアクタを作成し、インターフェースを実装する。
-
近くにあるオブジェクトの Interact インターフェース関数を呼び出すように BpCommunication Character クラスを変更します。
1 - 必要な設定
-
メニューの [New Project Categories (新規プロジェクトカテゴリ)] セクションにある [Games (ゲーム)] を選択して [Next (次へ)] をクリックします。
-
[Third Person (サードパーソン)] テンプレートを選択し、[Next] をクリックします。
-
[C++] プロジェクトを選択して [With Starter Content (スターター コンテンツあり)] オプションを有効化して [Create Project (プロジェクトの作成)] をクリックします。
このセクションの結果
新規のサードパーソン プロジェクトを作成し、インターフェースについて学ぶ準備ができました。
2 - インターフェースを作成する
-
C++ クラス ウィザード から、新規 Unreal インターフェース クラスを「InteractInterface」という名前で作成します。
-
「
IInteractInterface.h
」のクラス デフォルトで、以下のメソッドを実装します。public:
UFUNCTION() virtual void OnInteract() = 0;
-
コードをコンパイルします。
完成コード
InteractionInterface.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "InteractInterface.generated.h"
// このクラスを変更する必要はありません。
UINTERFACE(MinimalAPI)
class UInteractInterface : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class BPCOMMUNICATION_API IInteractInterface
{
GENERATED_BODY()
// このクラスにインターフェース関数を追加します。これは、このインターフェースを実装するために継承されるクラスです。
public:
UFUNCTION()
virtual void OnInteract() = 0;
};
このセクションの結果
このセクションでは、Unreal インターフェースを作成して「OnInteract」という関数を追加しました。これで、このインターフェースを実装するアクタ クラス ブループリントに、この関数を追加することができるようになりました。
2 - インタラクティブなシーリング ライト アクタを作成する
-
C++ クラス ウィザード から、新規アクタ クラスを「CeilingLight」という名前で作成します。
「CeilingLight.h」のクラス デフォルトで、以下のクラス ライブラリを実装します。
#include "InteractInterface.h"
次に、以下のコードを実装します。
UCLASS() class BPCOMMUNICATION_API ACeilingLight : public AActor, public IInteractInterface { GENERATED_BODY() public: virtual void OnInteract(); protected: UPROPERTY(EditAnywhere, BlueprintReadWrite) class UPointLightComponent* PointLightComp; UPROPERTY(EditAnywhere, BlueprintReadWrite) UStaticMeshComponent* StaticMeshComp; UPROPERTY(EditAnywhere, BlueprintReadWrite) float Brightness; UPROPERTY(EditAnywhere, BlueprintReadWrite) float SourceRadius; UPROPERTY(EditAnywhere, BlueprintReadWrite) FLinearColor Color; UPROPERTY(EditAnywhere, BlueprintReadWrite) bool bIsLightOn; UFUNCTION() void ToggleLight(); }
-
「CeilingLight.cpp」ファイルに移動し、次の Include ライブラリを宣言します。
#include "Components/PointLightComponent.h"
次に、以下のコードを実装します。
ACeilingLight::ACeilingLight() { // 各フレームでこのアクタが Tick() を呼び出すよう設定します。必要ない場合は、パフォーマンス向上のためにこれをオフにすることができます。 PrimaryActorTick.bCanEverTick = true; RootComponent = CreateDefaultSubobject<URootComponent>(TEXT("RootComponent")); PointLightComp = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComp")); StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComp")); PointLightComp->AttachToComponent(RootComponent,FAttachmentTransformRules::KeepRelativeTransform); StaticMeshComp->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform); PointLightComp->SetWorldLocation(FVector(0, 0, -130)); Brightness = 1700.f; Color = FLinearColor(1.f, 0.77f, 0.46f); SourceRadius = 3.5f; PointLightComp->SetIntensity(Brightness); PointLightComp->SetLightColor(Color); PointLightComp->SetSourceRadius(SourceRadius); } void ACeilingLight::OnInteract() { ToggleLight(); } void ACeilingLight::ToggleLight() { if (bbIsLightOn) { PointLightComp->SetVisibility(false); bbIsLightOn = false; } else { PointLightComp->SetVisibility(true); bbIsLightOn = true; } }
-
コードをコンパイルします。
-
「C++ Classes」フォルダから CeilingLight アクタを右クリックし、[C++ Class Actions (C++ クラス アクション)] ドロップダウンメニューから [Create Blueprint class based on CeilingLight (CeilingLight に基づいてブループリント クラスを作成する)] を選択します。ブループリントに「BP_CeilingLight」という名前を付けます。
-
BP_CeilingLight クラス デフォルトから、[Components (コンポーネント)] パネルに移動し、「StaticMeshComp」を選択します。
-
[Details (詳細)] パネルから [Static Mesh (スタティックメッシュ)] カテゴリに移動して Static Mesh 変数の隣にあるドロップダウンの矢印を選択し、「SM_Lamp_Ceiling」を検索、選択します。
完成コード
CeilingLight.h
// プロジェクト設定の説明ページの著作権表示を入力します。
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "InteractInterface.h"
#include "CeilingLight.generated.h"
UCLASS()
class BPCOMMUNICATION_API ACeilingLight : public AActor, public IInteractInterface
{
GENERATED_BODY()
public:
// このアクタのプロパティのデフォルト値を設定します。
ACeilingLight();
virtual void OnInteract();
protected:
// ゲームの開始時またはスポーン時に呼び出します。
virtual void BeginPlay() override;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UPointLightComponent* PointLightComp;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UStaticMeshComponent* StaticMeshComp;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Brightness;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float SourceRadius;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FLinearColor Color;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool bbIsLightOn;
public:
// フレームごとに呼び出します。
virtual void Tick(float DeltaTime) override;
UFUNCTION()
void ToggleLight();
};
CeilingLight.cpp
//Copyright Epic Games, Inc. All Rights Reserved.
#include "CeilingLight.h"
#include "Components/PointLightComponent.h"
// デフォルト値を設定します。
ACeilingLight::ACeilingLight()
{
// 各フレームでこのアクタが Tick() を呼び出すよう設定します。必要ない場合は、パフォーマンス向上のためにこれをオフにすることができます。
PrimaryActorTick.bCanEverTick = true;
RootComponent = CreateDefaultSubobject<URootComponent>(TEXT("RootComponent"));
PointLightComp = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComp"));
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComp"));
PointLightComp->AttachToComponent(RootComponent,FAttachmentTransformRules::KeepRelativeTransform);
StaticMeshComp->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
PointLightComp->SetWorldLocation(FVector(0, 0, -130));
Brightness = 1700.f;
Color = FLinearColor(1.f, 0.77f, 0.46f);
SourceRadius = 3.5f;
PointLightComp->SetIntensity(Brightness);
PointLightComp->SetLightColor(Color);
PointLightComp->SetSourceRadius(SourceRadius);
}
void ACeilingLight::OnInteract()
{
ToggleLight();
}
// ゲームの開始時またはスポーン時に呼び出します。
void ACeilingLight::BeginPlay()
{
Super::BeginPlay();
}
void ACeilingLight::ToggleLight()
{
if (bIsLightOn)
{
PointLightComp->SetVisibility(false);
bIsLightOn = false;
}
else
{
PointLightComp->SetVisibility(true);
bIsLightOn = true;
}
}
// フレームごとに呼び出します。
void ACeilingLight::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
このセクションの結果
このセクションでは、Ceiling Light アクタ クラスを作成し、ライトのオンとオフを切り替えるカスタム関数を追加しました。また、ToggleLight イベントの実行をトリガーする Interactインターフェースを実装しました。
4 - インタラクティブなドアを作成する
-
C++ クラス ウィザード で、新規 Actor クラスを「DoorActor」という名前で作成します。
-
「DoorActor.h」ファイルに移動し、次のように宣言します。
#include "Components/TimelineComponent.h" #include "InteractInterface.h"
-
DoorActor クラスの名前空間では、Interact インターフェースから継承する必要があります。
UCLASS() class BPCOMMUNICATION_API ADoorActor : public AActor, public IInteractInterface
-
以下のクラス定義を宣言します。
// カーブ アセットを保持するための変数 UPROPERTY(EditAnywhere) UCurveFloat* DoorTimelineFloatCurve; UFUNCTION() virtual void OnInteract(); protected: // ゲームの開始時またはスポーン時に呼び出します。 virtual void BeginPlay() override; //ドア アセットを表現するための MeshComponent UPROPERTY(VisibleAnywhere, BlueprintReadWrite) UStaticMeshComponent* DoorFrame; UPROPERTY(VisibleAnywhere, BlueprintReadWrite) UStaticMeshComponent* Door; //ドア メッシュをアニメートするための TimelineComponent UPROPERTY(VisibleAnywhere, BlueprintReadWrite) UTimelineComponent* DoorTimelineComp; //トラック イベントを更新するための Float トラック シグネチャ FOnTimelineFloat UpdateFunctionFloat; //タイムライン グラフに対するドアの相対位置を更新する関数 UFUNCTION() void UpdateTimelineComp(float Output);
-
「DoorActor.cpp」内で、次のクラス定義を実装します。
ADoorActor::ADoorActor() { //デフォルト コンポーネントを作成します。 DoorFrame = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorFrameMesh")); Door = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorMesh")); DoorTimelineComp = CreateDefaultSubobject<UTimelineComponent>(TEXT("DoorTimelineComp")); //アタッチメントを設定します。 DoorFrame->SetupAttachment(RootComponent); Door->AttachToComponent(DoorFrame, FAttachmentTransformRules::KeepRelativeTransform); Door->SetRelativeLocation(FVector(0, 35, 0)); } void ADoorActor::OnInteract() { DoorTimelineComp->Play(); } // ゲームの開始時またはスポーン時に呼び出します。 void ADoorActor::BeginPlay() { Super::BeginPlay(); //UpdateTimelineComp 関数の出力に Float トラックをバインドします。 UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp); //Float カーブがある場合は、そのグラフを更新関数にバインドします。 if (DoorTimelineFloatCurve) { DoorTimelineComp->AddInterpFloat(DoorTimelineFloatCurve, UpdateFunctionFloat); } } void ADoorActor::UpdateTimelineComp(float Output) { // ドアの新しい相対位置を、タイムライン カーブからの出力に基づいて作成および設定します。 FRotator DoorNewRotation = FRotator(0.0f, Output, 0.f); Door->SetRelativeRotation(DoorNewRotation); }
-
コードをコンパイルします。
-
コンテンツ ブラウザ で [Add/Import (追加/インポート)] > [Miscellaneous (その他)] > [Curve (カーブ)] を選択します。
-
[CurveFloat] を選択して CurveFloat アセットに「DoorCurveFloat」という名前を付けます。
-
DoorCurveFloat アセットをダブルクリックします。2 つのキーを Float カーブに追加し、1 つのキーに時間の値「(0,0)」を、もう 1 つ のキーに時間の値「(4,90)」を割り当てます。
-
Shift キーを押しながら 2 つのキーを選択して Auto Cubic interpolation に設定し、カーブを保存します。
-
DoorCurveFloat を保存します。
-
コンテンツ ブラウザから「C++ Classes」フォルダに移動して DoorActor クラスを右クリックします。[Create Blueprint Class based on Door Actor (Door アクタに基づいてブループリント クラスを作成する)] を選択し、「BP_DoorActor」という名前を付けます。
-
BP_DoorActor の [Class Defaults] 内で [Components] タブを探し、DoorFrame Static Mesh コンポーネント を選択して [Details] パネルに移動して [Static Mesh]を「SM_DoorFrame」に変更します。
-
次に、[Components] タブから DoorMesh コンポーネントを選択します。[Details] パネルに移動してスタティックメッシュを「SM_Door」に変更します。
-
[Details] パネルの [Door Timeline Float Curve (ドア タイムライン フロート カーブ)] から [DoorCurveFloat] を選択します。
-
ブループリントをコンパイルして保存します。
完成コード
DoorActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/TimelineComponent.h"
#include "InteractInterface.h"
#include "DoorActor.generated.h"
UCLASS()
class BPCOMMUNICATION_API ADoorActor : public AActor, public IInteractInterface
{
GENERATED_BODY()
public:
// このアクタのプロパティのデフォルト値を設定します。
ADoorActor();
// カーブ アセットを保持するための変数
UPROPERTY(EditAnywhere)
UCurveFloat* DoorTimelineFloatCurve;
UFUNCTION()
virtual void OnInteract();
protected:
// ゲームの開始時またはスポーン時に呼び出します。
virtual void BeginPlay() override;
//ドア アセットを表現するための MeshComponent
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* DoorFrame;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* Door;
//ドア メッシュをアニメートするための TimelineComponent
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UTimelineComponent* DoorTimelineComp;
//トラック イベントを更新するための Float トラック シグネチャ
FOnTimelineFloat UpdateFunctionFloat;
//タイムライン グラフに対するドアの相対位置を更新する関数
UFUNCTION()
void UpdateTimelineComp(float Output);
public:
// フレームごとに呼び出します。
virtual void Tick(float DeltaTime) override;
};
DoorActor.cpp
#include "DoorActor.h"
// デフォルト値を設定します。
ADoorActor::ADoorActor()
{
// 各フレームでこのアクタが Tick() を呼び出すよう設定します。必要ない場合は、パフォーマンス向上のためにこれをオフにすることができます。
PrimaryActorTick.bCanEverTick = true;
//デフォルト コンポーネントを作成します。
DoorFrame = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorFrameMesh"));
Door = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorMesh"));
DoorTimelineComp = CreateDefaultSubobject<UTimelineComponent>(TEXT("DoorTimelineComp"));
//アタッチメントを設定します。
DoorFrame->SetupAttachment(RootComponent);
Door->AttachToComponent(DoorFrame, FAttachmentTransformRules::KeepRelativeTransform);
Door->SetRelativeLocation(FVector(0, 35, 0));
}
void ADoorActor::OnInteract()
{
DoorTimelineComp->Play();
}
// ゲームの開始時またはスポーン時に呼び出します。
void ADoorActor::BeginPlay()
{
Super::BeginPlay();
//UpdateTimelineComp 関数の出力に Float トラックをバインドします。
UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp);
//Float カーブがある場合は、そのグラフを更新関数にバインドします。
if (DoorTimelineFloatCurve)
{
DoorTimelineComp->AddInterpFloat(DoorTimelineFloatCurve, UpdateFunctionFloat);
}
}
void ADoorActor::UpdateTimelineComp(float Output)
{
// ドアの新しい相対位置を、タイムライン カーブからの出力に基づいて作成および設定します。
FRotator DoorNewRotation = FRotator(0.0f, Output, 0.f);
Door->SetRelativeRotation(DoorNewRotation);
}
// フレームごとに呼び出します。
void ADoorActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
このセクションの結果
このセクションでは、Interact インターフェースの OnInteract メソッドが呼び出されたときに開くインタラクティブな Door アクタを作成しました。
5 - BPCommunicationCharacter クラスを変更する
- 「BpCommunicationCharacter.h」ファイルを開き、以下のクラス定義を宣言します。
protected: virtual void NotifyActorBeginOverlap(AActor* OtherActor); class USphereComponent* SphereComp;
-
「BpCommunicationCharacter.cpp」ファイルに移動し、以下のクラス ライブラリを宣言します。
#include "Components/SphereComponent.h" #include "InteractInterface.h"
次に、以下のクラス メソッドを実装します。
ABPCommunicationCharacter::ABPCommunicationCharacter() { SphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp")); SphereComp->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform); SphereComp->SetSphereRadius(200); } void ABPCommunicationCharacter::NotifyActorBeginOverlap(AActor* OtherActor) { if (IInteractInterface* ActorCheck = Cast<IInteractInterface>(OtherActor)) { ActorCheck->OnInteract(); } }
- コードをコンパイルします。
完成コード
BpCommunicationCharacter.h
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "BPCommunicationCharacter.generated.h"
UCLASS(config=Game)
class ABPCommunicationCharacter : public ACharacter
{
GENERATED_BODY()
/** キャラクターの後ろにカメラを配置するカメラ ブーム*/
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class USpringArmComponent* CameraBoom;
/** カメラをフォローします。*/
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class UCameraComponent* FollowCamera;
public:
ABPCommunicationCharacter();
/** 基本回転速度 (度/秒)。最終的なターン率が他のスケーリングの影響を受ける場合があります。*/
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseTurnRate;
/** 基本ルックアップ/ダウン レート (度/秒)。最終的なレート (率) が他のスケーリングの影響を受ける場合があります。*/
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseLookUpRate;
protected:
virtual void NotifyActorBeginOverlap(AActor* OtherActor);
class USphereComponent* SphereComp;
/** VR での HMD の向きをリセットします。*/
void OnResetVR();
/** 前方/後方入力のために呼び出されます。*/
void MoveForward(float Value);
/** 左右の入力のために呼び出されます。*/
void MoveRight(float Value);
/**
* 任意の率でターンするよう、入力を介して呼び出されます。
* @param Rate これは正規化された率で、「1.0」は希望のターン率を 100% 実現していることを意味します。
*/
void TurnAtRate(float Rate);
/**
* 任意の率でルックアップ/ルックダウンをターンするよう、入力を介して呼び出されます。
* @param Rate これは正規化された率で、「1.0」は希望のターン率を 100% 実現していることを意味します。
*/
void LookUpAtRate(float Rate);
/** タッチ入力が開始されたときのハンドラ。*/
void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);
/** タッチ入力が停止したときのハンドラ。*/
void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);
protected:
// APawn インターフェース
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// APawn インターフェースの終了
public:
/** CameraBoom サブオブジェクトを返します。**/
FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
/** FollowCamera サブオブジェクトを返します。**/
FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
};
BpCommunicationCharacter.cpp
// Copyright Epic Games, Inc. All Rights Reserved.
#include "BPCommunicationCharacter.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "Components/SphereComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "InteractInterface.h"
#include "GameFramework/SpringArmComponent.h"
//////////////////////////////////////////////////////////////////////////
// ABPCommunicationCharacter
ABPCommunicationCharacter::ABPCommunicationCharacter()
{
// コリジョン カプセルのサイズを設定します。
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
// 入力のターン率を設定します。
BaseTurnRate = 45.f;
BaseLookUpRate = 45.f;
// コントローラーが回転するときは回転させないでください。影響を受けるのはカメラのみにします。
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// キャラクターの動きを設定します。
GetCharacterMovement()->bOrientRotationToMovement = true; // 入力した方向にキャラクターが移動します...
GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...この回転速度で実行します。
GetCharacterMovement()->JumpZVelocity = 600.f;
GetCharacterMovement()->AirControl = 0.2f;
// カメラ ブームを作成します (コリジョンがある場合はプレイヤーに向かって引きます)。
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(RootComponent);
CameraBoom->TargetArmLength = 300.0f; // カメラがキャラクターの後ろをこの距離で追跡します。
CameraBoom->bUsePawnControlRotation = true; // コントローラーを基準にアームを回転させます。
// 追跡するカメラを作成します。
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // ブームの最後にカメラをアタッチして、コントローラーの方向と一致するようブーム自身に調整させます。
FollowCamera->bUsePawnControlRotation = false; // カメラは腕の動きに合わせて回転しません。
SphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp"));
SphereComp->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform);
SphereComp->SetSphereRadius(200);
// 注:メッシュ コンポーネント上のスケルタルメッシュと Anim ブループリントの参照 (キャラクターから継承) は、
// MyCharacter という名前の、派生したブループリント アセットで設定されます (C++ での直接のコンテンツ参照を回避するため)。
}
//////////////////////////////////////////////////////////////////////////
// 入力
void ABPCommunicationCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
// ゲームプレイ キー バインディングを設定します。
check(PlayerInputComponent);
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
PlayerInputComponent->BindAxis("MoveForward", this, &ABPCommunicationCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &ABPCommunicationCharacter::MoveRight);
// さまざまなデバイスをそれぞれ処理するための回転バインディングには 2 つのバージョンがあります。
// 「turn」では、マウスなどの絶対デルタを提供するデバイスを処理します。
// 「turnrate」は、アナログのジョイスティックなど、ユーザーが「変更率」として処理することに決めたデバイス向けです。
PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
PlayerInputComponent->BindAxis("TurnRate", this, &ABPCommunicationCharacter::TurnAtRate);
PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
PlayerInputComponent->BindAxis("LookUpRate", this, &ABPCommunicationCharacter::LookUpAtRate);
// タッチ デバイスを処理します。
PlayerInputComponent->BindTouch(IE_Pressed, this, &ABPCommunicationCharacter::TouchStarted);
PlayerInputComponent->BindTouch(IE_Released, this, &ABPCommunicationCharacter::TouchStopped);
// VR ヘッドセットの機能
PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &ABPCommunicationCharacter::OnResetVR);
}
void ABPCommunicationCharacter::NotifyActorBeginOverlap(AActor* OtherActor)
{
if (IInteractInterface* ActorCheck = Cast<IInteractInterface>(OtherActor))
{
ActorCheck->OnInteract();
}
}
void ABPCommunicationCharacter::OnResetVR()
{
// BPCommunication が Unreal Editor の [Add Feature (機能を追加)] からプロジェクトに追加される場合、BPCommunication.Build.cs の依存関係は自動的に反映されず、
// リンカのエラーが発生します。
// 以下のいずれかを行う必要があります。
// 正常にビルドを行うために「HeadMountedDisplay」を [YourProject].Build.cs PublicDependencyModuleNames に追加します (VR をサポートしている場合に適切)。
// または:
// 以下の ResetOrientationAndPosition への呼び出しをコメントにするか、または削除します (VR をサポートしていない場合に適切)
UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}
void ABPCommunicationCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
Jump();
}
void ABPCommunicationCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
StopJumping();
}
void ABPCommunicationCharacter::TurnAtRate(float Rate)
{
// 率に関する情報からこのフレームのデルタを計算します。
AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}
void ABPCommunicationCharacter::LookUpAtRate(float Rate)
{
// 率に関する情報からこのフレームのデルタを計算します。
AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}
void ABPCommunicationCharacter::MoveForward(float Value)
{
if ((Controller != nullptr) && (Value != 0.0f))
{
// どちらが前方かを調べます。
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// get forward ベクター
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
}
void ABPCommunicationCharacter::MoveRight(float Value)
{
if ( (Controller != nullptr) && (Value != 0.0f) )
{
// どちらが右かを調べます。
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// get right ベクター
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
// その方向に動きを追加します。
AddMovementInput(Direction, Value);
}
}
このセクションの結果
このセクションでは、Sphere コンポーネントを、オーバーラップするアクタの検出を行う ThirdPersonCharacter クラスに追加しました。アクタが球形にオーバーラップすると、キャラクターがキャスティングしてインターフェースとインタラクトし、オーバーラップしているアクタに OnInteract 関数をトリガーします。
6 - インタラクション システムをテストする
-
BP_DoorActor のインスタンスと BP_CeilingLamp ブループリントをレベル ビューポートにドラッグします。
-
[Play (プレイ)] を押して、各ブループリントに近づいたときのプレイヤーとのインタラクションを確認します。
このセクションの結果
このセクションでは、インタラクティブなドアとシーリング ランプのアクタ ブループリントでテストし、インタラクション システムが意図したとおりに動作することを確認しました。
このクイック スタート ガイドでは、各アクタ クラス ブループリントに同一のインターフェースを実装し、別々の関数を指定する方法を学習しました。また、インターフェースがさまざまなブループリント クラスの類似の関数を実装するのに適しており、キャスティングを必要としない理由も学びました。
次のステップ
ブループリント インターフェースの使い方が分かったところで、今度は アクタ通信 ドキュメント ページで参照されている他の通信手段を見てみましょう。