Interface クラスは関連性のない一連のクラスが共通の関数を実装するために使用されます。これは、あるゲーム機能が類似性のない大きく複雑なクラスによって共有されている場合に役立ちます。
ゲームにはプレイヤー キャラクターがトリガー ボリュームに入るとトラップを起動したり、敵に警告したり、プレイヤーにポイントを付与したりできるようなシステムがあります。トラップや敵、ポイント報酬には「ReactToTrigger」関数が実装されている可能性がありますが、トラップは AActor から、敵は特殊な APawn または ACharacter サブクラスから、ポイント報酬は UDataAsset
から派生することもあります。
こうしたクラスにはすべて共有の機能を必要としますが、UObject
以外は共通の親がありません。その場合、インターフェースをお勧めします。
インターフェースの宣言
インターフェース クラスの宣言は、通常の Unreal クラスの宣言と似ていますが、大きな違いが 2 つあります。まず、インターフェース クラスでは UCLASS マクロの代わりに UINTERFACE マクロを使用し、直接 UObject
からではなく UInterface
から継承します。
UINTERFACE([specifier, specifier, ...], [meta(key=value, key=value, ...)])
class UClassName : public UInterface
{
GENERATED_BODY()
};
次に、UINTERFACE クラスは実際のインターフェースではありません。Unreal Engine のリフレクション システムで見えるようにするためだけに存在する空のクラスです。他のクラスによって継承される実際のインターフェースには必ず同じクラス名が設定されますが、最初の「U」が「I」に変更されています。
.h ファイル (例:ReactToTriggerInterface.h
) で次のようにします。
#pragma once
#include "ReactToTriggerInterface.generated.h"
UINTERFACE(MinimalAPI, Blueprintable)
class UReactToTriggerInterface : public UInterface
{
GENERATED_BODY()
};
class IReactToTriggerInterface
{
GENERATED_BODY()
public:
/** インターフェース関数の宣言をここに追加します*/
};
「U のプレフィックスが付いた」クラスはコンストラクタや他の関数を必要としません。「I のプレフィックスが付いた」クラスはすべてのインターフェース関数を含み、他のクラスによって実際に継承されるものになります。
ブループリントにこのインターフェースを実装する場合は、Blueprintable
指定子が必要です。
インターフェース指定子
インターフェース指定子を使用して、クラスを Unreal リフレクション システムに公開します。次の表を参照してください。
インターフェース指定子 | 意味 |
---|---|
BlueprintType |
このクラスを、ブループリントの変数に使用できる型として公開します。 |
DependsOn=(ClassName1, ClassName2, ...) |
リストされているクラスはすべて、このクラスより前にコンパイルされます。ClassName は同じ (あるいは以前の) パッケージのクラスを指定する必要があります。1 行の DependsOn 行をカンマで区切って使用したり、クラスごとに別の DependsOn 行を使用することで、複数の依存クラスを指定することができます。コンパイラはクラス内のコンパイル済みのものしか認識しないため、これは他のクラスで宣言された構造体や列挙型変数をクラスで使う場合に重要となります。 |
MinimalAPI |
他のモジュールで使用するために、クラスの型情報のみをエクスポートさせます。クラスをキャストすることができますが、クラスの関数を呼び出すことはできません (インライン メソッドは除く)。これにより、他のモジュールではアクセスできる関数のすべてを必要としないクラスの場合はすべてをエクスポートせずに済むため、コンパイル時間を短縮できます。 |
C++ でインターフェースを実装する
新規クラスでインターフェースを使用するには、(使用している UObject
ベースのクラスに加えて) 「I のプレフィックスが付いた」インターフェース クラスから継承します。
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ReactToTriggerInterface.h"
#include "Trap.generated.h"
UCLASS(Blueprintable, Category="MyGame")
class ATrap : public AActor, public IReactToTriggerInterface
{
GENERATED_BODY()
public:
/** インターフェース関数のオーバーライドをここに追加します。*/
}
インターフェース関数を宣言する
インターフェースで関数を宣言する方法は何種類かありますが、実装や呼び出しが可能な状況はそれぞれ異なります。すべての関数は「I のプレフィックスが付いた」クラスでインターフェースに対して宣言し、外部クラスからも見えるように public
にする必要があります。
C++ インターフェースのみの関数
インターフェースのヘッダ ファイルで UFUNCTION
指定子を付けずに仮想 C++ 関数を宣言することができます。インターフェースを実装するクラスでオーバーライドできるように関数は仮想でなければなりません。
public:
virtual bool ReactToTrigger();
ヘッダ内またはインターフェースの .cpp
ファイル内のいずれかで、デフォルトの実装を指定できます。
bool IReactToTriggerInterface::ReactToTrigger()
{
return false;
}
Actor クラスでインターフェースを実装する場合、そのクラス固有のオーバーライドを作成して実装できます。
Trap.h public:
virtual bool ReactToTrigger() override;
Trap.cpp
bool ATrap::ReactToTrigger()
{
return false;
}
ただし、これらの C++ インターフェース関数はブループリントでは表示されません。
ブループリントでの呼び出しが可能なインターフェース関数
ブループリントでの呼び出しが可能なインターフェース関数を作成するには、BlueprintCallable
指定子を使用した関数宣言で UFUNCTION
マクロを指定する必要があります。また、BlueprintImplementableEvent
指定子か BlueprintNativeEvent
指定子のいずれかを使用する必要があり、関数は仮想であってはなりません。
public:
/**ブループリントでのみ実装できる React To Trigger のバージョン。*/
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category=Trigger Reaction)
bool ReactToTrigger();
ReactToTrigger.h
public:
/**C++ またはブループリントで実装できる React To Trigger のバージョン。*/
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category=Trigger Reaction)
bool ReactToTrigger();
BlueprintCallable
BlueprintCallable
指定子を使用した関数は、インターフェースを実装するオブジェクトへの参照を使用して C++ またはブループリントで呼び出すことができます。
BlueprintImplementableEvent
BlueprintImplementableEvent
を使用した関数は C++ でオーバーライドすることはできませんが、インターフェースを実装または継承しているブループリント クラスではオーバーライドが可能です。
BlueprintNativeEvent
BlueprintNativeEvent
を使用した関数は同じ名前の関数をオーバーライドすることによって C++ で実装することができますが、末尾にサフィックス _Implementation
を追加します。
public:
bool ReactToTrigger_Implementation() override;
Trap.cpp
bool ATrap::ReactToTrigger_Implementation() const
{
return false;
}
この指定子は実装をブループリントでオーバーライドすることも可能です。
任意のクラスがインターフェースを実装するかを判断する
インターフェースを実装する C++ とブループリントのクラスの両方で互換性を得るために、次のいずれかの関数を使用します。
bool bIsImplemented = OriginalObject->GetClass()->ImplementsInterface(UReactToTriggerInterface::StaticClass()); // OriginalObject が UReactToTriggerInterface を実装していれば bIsImplemented は true になります。
bIsImplemented = OriginalObject->Implements<UReactToTriggerInterface>(); // OriginalObject が UReactToTriggerInterface を実装していれば bIsImplemented は true になります。
IReactToTriggerInterface* ReactingObjectA = Cast<IReactToTriggerInterface>(OriginalObject); // OriginalObject が UReactToTriggerInterface を実装していれば ReactingObject は Null 以外になります。
StaticClass
関数が「I のプレフィックスが付いた」クラスで実装されていない場合、「U のプレフィックスが付いた」クラスで Cast
の使用を試みると失敗し、コードもコンパイルされません。
他の Unreal タイプにキャスティングする
Unreal Engine のキャスティング システムでは、あるインターフェースから別のインターフェースへのキャスティング、または、あるインターフェースからある Unreal タイプへのキャスティングを適宜サポートしています。
IReactToTriggerInterface* ReactingObject = Cast<IReactToTriggerInterface>(OriginalObject); // インターフェースが実装されている場合、ReactingObject は Null 以外になります。
ISomeOtherInterface* DifferentInterface = Cast<ISomeOtherInterface>(ReactingObject); // ReactingObject が Null ではなく、ISomeOtherInterface を実装している場合、DifferentInterface は Null 以外になります。
AActor* Actor = Cast<AActor>(ReactingObject); // ReactingObject が Null ではなく、OriginalObject が AActor または AActor 派生クラスの場合、アクタは Null 以外になります。
ブループリントに実装可能なクラス
ブループリントにこのインターフェースを実装させる場合、Blueprintable
メタデータ指定子を使用する必要があります。Blueprint クラスがオーバーライドしようとするインターフェース関数はすべて、BlueprintNativeEvent
または BlueprintImplementableEvent
でなければなりません。BlueprintCallable
としてマークされる関数も呼び出し可能ですが、オーバーライドはされません。他のすべての関数は、ブループリントからアクセスできません。