- 简单的说,接口提供一组公共的方法,不同的对象中继承这些方法后可以有不同的具体实现。
- 任何使用接口的类都必须实现这些接口。
- 实现解耦
- 解决多继承的问题
蓝图使用
使用方法
三种调用方法的区别
调用流关卡蓝图的接口函数
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);
}
}
测试结果
参考
|
请发表评论