概述
- 簡單的說,接口提供一組公共的方法,不同的對象中繼承這些方法后可以有不同的具體實現。
- 任何使用接口的類都必須實現這些接口。
- 實現解耦
- 解決多繼承的問題
藍圖使用
使用方法
三種調用方法的區別
調用流關卡藍圖的接口函數
C++ 使用接口
本例使用一個Box Trigger 出發overlap 調用 Drone實例的接口
添加接口類
定義接口
聲明藍圖可調用接口函數
-
用UFUNCTION 宏
BlueprintCallable
聲明藍圖可調用,還必須使用BlueprintImplementableEvent
或BlueprintNativeEvent
說明,而且函數不能為虛函數 -
如果不想藍圖重載,只是想使用
BlueprintCallable
以支持藍圖起到單純的調用作用,可以通過將接口標記為UINTERFACE(meta = (CannotImplementInterfaceInBlueprint))
來解決 -
通過聲明 virtual 虛函數,使得派生類可重載
代碼
-
ReactToTriggerInterface.h
#pragma once #include "CoreMinimal.h" #include "UObject/Interface.h" #include "ReactToTriggerInterface.generated.h" // 無需更改 // UINTERFACE類不是實際的接口;它是一個空白類,它的存在只是為了向虛幻引擎反射系統確保可見性。 UINTERFACE(MinimalAPI) class UReactToTriggerInterface : public UInterface { GENERATED_BODY() }; //開頭字母"U"必須改為"I"。 class TIPS_API IReactToTriggerInterface { GENERATED_BODY() public: // 純虛函數,實現類必須實現接口 virtual void ReactToTrigger_PureVirtual() = 0; // 虛函數,在接口本身的 .h 或 .cpp 文件中提供默認實現.實現類可覆蓋 virtual void ReactToTrigger_Virtual(); //實現類可以在藍圖和C++中實現接口 UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="Trigger Reaction") void ReactToTrigger_NativeEvent1(int32 number); //實現類可以在藍圖和C++中實現接口 UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Trigger Reaction") bool ReactToTrigger_NativeEvent2(int32 number); //實現類在藍圖中實現接口 UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category = "Trigger Reaction") void ReactToTrigger_ImplementableEvent(); };
-
ReactToTriggerInterface.cpp
#include "ReactToTriggerInterface.h" void IReactToTriggerInterface::ReactToTrigger_Virtual() { // unimplemented(); //該宏將在執行代碼行時發出調試語句, 中斷 UE_LOG(LogTemp, Warning, TEXT("ReactToTrigger_Virtual 被調用, From 接口本身")); }
實現接口
-
MyDrone.h 此類繼承自Pawn類,無關本文主題
#include "ReactToTriggerInterface.h" #include "MyDrone.generated.h" UCLASS() class TIPS_API AMyDrone : public ADrone, public IReactToTriggerInterface { GENERATED_BODY() public: virtual void ReactToTrigger_PureVirtual() override; //可藍圖調用,貌似通用寫法 UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Trigger Reaction") void ReactToTrigger_NativeEvent1(int32 number); virtual void ReactToTrigger_NativeEvent1_Implementation(int32 number) override; //藍圖可調用,,貌似和上面沒區別 virtual bool ReactToTrigger_NativeEvent2_Implementation(int32 number) override; //void ReactToTrigger_ImplementableEvent();需要在藍圖實現 };
-
MyDrone.cpp
#include "MyDrone.h" void AMyDrone::ReactToTrigger_PureVirtual() { UE_LOG(LogTemp, Warning, TEXT("ReactToTrigger_PureVirtual 被調用, From MyDrone")); } void AMyDrone::ReactToTrigger_NativeEvent1_Implementation(int32 number) { UE_LOG(LogTemp, Warning, TEXT("ReactToTrigger_NativeEvent1 被調用, From MyDrone")); } bool AMyDrone::ReactToTrigger_NativeEvent2_Implementation(int32 number) { UE_LOG(LogTemp, Warning, TEXT("ReactToTrigger_NativeEvent2 被調用, From MyDrone")); return true; }
-
也可以藍圖重載
調用接口的類
-
c++ 調用接口可以先判斷該類是否有實現接口
// 如果OriginalObject實現了UReactToTriggerInterface,則bisimplemated將為true。 bool bIsImplemented = OriginalObject->GetClass()->ImplementsInterface(UReactToTriggerInterface::StaticClass()); // 如果OriginalObject實現了UReactToTrigger,bIsImplemented將為true。 bIsImplemented = OriginalObject->Implements<UReactToTriggerInterface>(); // 如果OriginalObject實現了UReactToTriggerInterface,則ReactingObject將為非空。 IReactToTriggerInterface* ReactingObject = Cast<IReactToTriggerInterface>(OriginalObject);
-
原生 虛函數調用按照原生C++調用即可
-
UFUCNTION()修飾的接口函數則以
I接口名::Execute_函數名( 接口實例, 函數參數)
調用
代碼
-
MyTriggerBox.h
#pragma once #include "CoreMinimal.h" #include "Engine/TriggerBox.h" #include "MyTriggerBox.generated.h" UCLASS() class TIPS_API AMyTriggerBox : public ATriggerBox { GENERATED_BODY() public: virtual void BeginPlay() override; UFUNCTION() void HandleOverlap(AActor* OverlappedActor, AActor* OtherActor ); };
-
MyTriggerBox.cpp
#include "MyTriggerBox.h" #include "Components/BoxComponent.h" #include "ReactToTriggerInterface.h" void AMyTriggerBox::BeginPlay() { //放在構造函數好像不起作用 OnActorBeginOverlap.AddDynamic(this, &AMyTriggerBox::HandleOverlap); } void AMyTriggerBox::HandleOverlap(AActor* OverlappedActor, AActor* OtherActor ) { UClass* ActorClass = OtherActor->GetClass(); if (ActorClass->ImplementsInterface(UReactToTriggerInterface::StaticClass())) { UE_LOG(LogTemp, Warning, TEXT("是否實現接口判斷方法一")); IReactToTriggerInterface* ReactToTriggerInterface1 = CastChecked<IReactToTriggerInterface>(OtherActor); ReactToTriggerInterface1->ReactToTrigger_PureVirtual(); ReactToTriggerInterface1->ReactToTrigger_Virtual(); IReactToTriggerInterface::Execute_ReactToTrigger_NativeEvent1(OtherActor, 16); IReactToTriggerInterface::Execute_ReactToTrigger_NativeEvent2(OtherActor, 32); IReactToTriggerInterface::Execute_ReactToTrigger_ImplementableEvent(OtherActor); } if (OtherActor->Implements<UReactToTriggerInterface>()) { UE_LOG(LogTemp, Warning, TEXT("是否實現接口判斷方法二")); IReactToTriggerInterface::Execute_ReactToTrigger_NativeEvent1(OtherActor, 16); IReactToTriggerInterface::Execute_ReactToTrigger_NativeEvent2(OtherActor, 32); } IReactToTriggerInterface* ReactToTriggerInterface2 = Cast<IReactToTriggerInterface>(OtherActor); if (ReactToTriggerInterface2) { UE_LOG(LogTemp, Warning, TEXT("是否實現接口判斷方法三")); IReactToTriggerInterface::Execute_ReactToTrigger_ImplementableEvent(OtherActor); } }