【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

参考

posted @ 2021-04-25 17:43  砥才人  阅读(3477)  评论(0编辑  收藏  举报