LoginSignup
9
9

More than 3 years have passed since last update.

UE4 インターフェイスについてのメモ

Posted at

概要

UnrealEngine のインターフェイスについてのメモ書きです。

環境

Windows10
Visual Studio 2017
UnrealEngine 4.25

参考

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

Unreal Engine : 公式
【Unreal C++】⑥Interface【UE4】
Interfaces In C++ | UE4 Community Wiki
【UE4】InterfaceとDispatcherの使い分け方-自分流

インターフェイスについて

インターフェイスは実装を縛る仕組みでクラスの依存度を下げるのに有用です。
C++にはインターフェイスがないため継承や純粋仮想クラスを使ったインターフェイスクラスで実現していますが、Unreal C++ も似たような感じのようです。

BPにてアクセスしたい相手BPクラスにキャストするケースがありますが、こういう場合にインターフェイスを使うことが望ましいようです。これはBPの参照が増えることによるビルド時間が延びてしまうことを抑えることができるためだと思われます。

Unreal C++ でのインターフェイス作成1

インターフェイス定義

UInterface を継承したクラスを宣言し、UプリフィックスをIに変えたクラスを宣言し、実装を縛るメソッドを宣言します。この時、GENERATED_***_BODY() が UI で違うことに注意。

またメタ情報の CannotImplementInterfaceInBlueprint はC++での実装に制限する指定です。

MyInterface.h
#pragma once

#include "CoreMinimal.h"
#include "MyIntarface.generated.h"

UINTERFACE(BlueprintType, meta = (CannotImplementInterfaceInBlueprint))
class MYPROJECT2_API UPerson : public UInterface
{
    GENERATED_UINTERFACE_BODY()
};

class MYPROJECT_API IPerson
{
    GENERATED_IINTERFACE_BODY()

public:
    // 実装したいメソッド
    virtual FString     Greeting();
};

Uプリフィックスのコンストラクタと、Iプリフィックスの実装メソッドデフォルト実装を書きます。この時点でインターフェイスぽくないです。。

MyInterface.cpp
#include "MyInterface.h"

UPerson::UPerson(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
}

FString IPerson::Greeting()
{
    return( FString(TEXT("....")) );
}

C++でインターフェイスを実装する

あとはインターフェイスクラスを継承してクラス宣言します。

MyClass.h

UCLASS()
class MYPROJECT_API UJapanese : public UObject, public IPerson
{
    GENERATED_BODY()

public:
    // オーバーライドする
    virtual FString     Greeting() override { return( FString::Printf(TEXT("こんにちは!")) ); }
};

デフォルト実装を持っているので、そちらを呼び出すこともできます。

MyClass.h
UCLASS()
class MYPROJECT_API UAmerican : public UObject, public IPerson
{
    GENERATED_BODY()

public:
    // 元の実装を呼び出す
    virtual FString     Greeting() override { return(IPerson::Greeting()); }
};

Unreal C++ でのインターフェイス作成2

インターフェイス定義

BlueprintImplementableEvent BlueprintNativeEvent をつけたインターフェイスを定義します。

MySampleInterface.h
#pragma once
#include "MySampleInterface.generated.h"

UINTERFACE(Blueprintable)
class UMySampleInterface : public UInterface
{
    GENERATED_UINTERFACE_BODY()
};

class IMySampleInterface
{
    GENERATED_IINTERFACE_BODY()

public:

    UFUNCTION(Category="Test", BlueprintImplementableEvent, BlueprintCallable)
    void Func0();
    UFUNCTION(Category="Test", BlueprintImplementableEvent, BlueprintCallable)
    void Func0Arg(int32 Value);
    UFUNCTION(Category="Test", BlueprintNativeEvent, BlueprintCallable)
    int32 Func1();
    UFUNCTION(Category="Test", BlueprintNativeEvent, BlueprintCallable)
    int32 Func1Arg(int32 Value);
};
MySampleInterface.cpp
#include "MySampleInterface.h"

UMySampleInterface::UMySampleInterface(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
}

実装インターフェイス

実装インターフェイス で実装してみます。
Implementation_Setting.jpg

関数は以下の様になります。
Implementation_Func.jpg

Func0Func0Arg はイベントで実装します。
Func0_BP.jpg

Func1Func1Arg は関数で実装します。
Func1_BP.jpg

Func1Arg_BP.jpg

呼び出しテスト

以下のコードを使ってインターフェイスの呼び出しを行います。

.cpp
#include "Kismet/GameplayStatics.h"

TArray<AActor*> _TargetActors;
// インターフェース取得
UGameplayStatics::GetAllActorsWithInterface(this->GetWorld(), UMySampleInterface::StaticClass(), _TargetActors);
// インターフェースを実行
for (auto _Actor : _TargetActors)
{
    IMySampleInterface::Execute_Func0(_Actor);
    IMySampleInterface::Execute_Func0Arg(_Actor, 100);
    IMySampleInterface::Execute_Func1(_Actor);
    IMySampleInterface::Execute_Func1Arg(_Actor, 200);
}

BPで呼び出す場合は以下の様になります。
execute_interfaceBP.jpg

以下の様になりました。問題なく呼び出せました。
Result.jpg

継承インターフェイス

継承インターフェイス で実装してみます。
Inheritance_Setting.jpg

関数は以下の様になります。
Inheritance_Func.jpg

実装インターフェイスの場合と同様に実装でき、同様の結果になります。

BPでインターフェイスを実装する

BPエディタで開いて
[クラス設定] -> [詳細] -> [インターフェイス] で追加できます。

BP_ClassSetting.jpg

CannotImplementInterfaceInBlueprint を付与したインターフェイスは実装インターフェイスでは追加できません。

継承インターフェイス はBPが継承したクラスが実装しているインターフェイスが表示されます。

BP でのインターフェイス作成

インターフェイス定義

コンテンツフォルダから右クリックで「ブループリントインターフェイス」で作成できます。
interfaceBP.jpg

BPインターフェイスにて関数名や引き数、返り値が設定できます。
interfaceBP_Setting.jpg

BPクラスでの実装

このBPインターフェイスを実装したいBPクラスに対し実装インターフェイスで追加して使用します。[クラス設定] -> [詳細] -> [インターフェイス]

追加するとインターフェイスイベントを実装できるようになります。

interfaceBP_Event.jpg

まとめ

UEのインターフェイスはイベントメッセージ的な面が強い気がします。
クラスの依存度を下げるためにも積極的に使っていきたいところですが、定義の記述方法はもう少しどうにかなりませんかね。。

9
9
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
9
9