【UE4 C++ 基礎知識】<9> Interface 接口


概述

  • 簡單的說,接口提供一組公共的方法,不同的對象中繼承這些方法后可以有不同的具體實現。
  • 任何使用接口的類都必須實現這些接口。
  • 實現解耦
  • 解決多繼承的問題

藍圖使用

使用方法

image

三種調用方法的區別

image

調用流關卡藍圖的接口函數

image

C++ 使用接口

本例使用一個Box Trigger 出發overlap 調用 Drone實例的接口

添加接口類

image

定義接口

聲明藍圖可調用接口函數

  • 用UFUNCTION 宏 BlueprintCallable 聲明藍圖可調用,還必須使用 BlueprintImplementableEventBlueprintNativeEvent 說明,而且函數不能為虛函數

  • 如果不想藍圖重載,只是想使用 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;
    }
    

    image

  • 也可以藍圖重載

    image

調用接口的類

  • 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);
    	}
    
    }
    

測試結果

image

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM