在虚幻引擎中实现蓝图接口 | 虚幻引擎 5.6 文档 | Epic Developer Community
虚幻引擎中的接口 | 虚幻引擎 5.6 文档 | Epic Developer Community
一.类向导里创建Interface
二.创建ReactToTriggerInterface接口
1.U类负责反射,I类负责逻辑。
U类负责反射,因为反射都需要继承自UObject。在I类里面实现,是为了防止菱形继承。
反射系统是选择加入的,只有主动标记的类型、属性、方法会被反射系统追踪, UnrealHeaderTool 会收集这些信息,生成用于支持反射机制的C++代码,然后再编译工程。 UObject是反射系统的核心。 每一个继承UObject且支持反射系统的类型都有一个相应的UClass,或者它的子类,UClass中包含了该类的描述信息。
2.声明定义
BlueprintNativeEvent,用了虚函数实现的方式。在接口里可以实现 C++ 默认接口。也可以不实现。实现的话,需要加virtual和_Implementation,先声明再定义。但不建议BlueprintNativeEvent的接口,直接在内部定义。因为它一定会被,继承的类重载,哪怕代码一摸一样,你也要抄一份过去,他最终调用的是继承接口的派生类的,这一点与C++思想一样。C++的接口是定义纯虚函数 = 0,在派生类必须重载。在接口的定义BlueprintNativeEvent的函数没用意义。也就是BumpTntoToTrigger_Implementation()是没啥意义的。
有一个方式可以用接口默认方法,但是那个不安全。不建议使用,就是不声明BumpTntoToTrigger所有相关的函数。但却使用这个接口。无论是官方文档还是源代码报错的地方都不建议这样做。
virtual void BumpTntoToTrigger_Implementation(); // 在接口中实现一个默认的 接口函数
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ReactToTriggerInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UReactToTriggerInterface : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class GWXPJ_API IReactToTriggerInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
// 此接口可以在接口的.cpp中定义一个默认的实现,并且只能在C++中重写
virtual bool ReactToTrigger();
// 只能在蓝图中重写
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
void TouchedToTrigger();
// 能在 蓝图 与 C++ 中重写。可以在接口的.cpp文件中实现一个默认的 接口函数。但是这里没有实现
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
bool SteppedToTrigger();
// 能在 蓝图 与 C++ 中重写。可以在接口的.cpp文件中实现一个默认的 接口函数。
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
void BumpTntoToTrigger();
virtual void BumpTntoToTrigger_Implementation(); // 在接口中实现一个默认的 接口函数
};
#include "ReactToTriggerInterface.h"
// Add default functionality here for any IReactToTriggerInterface functions that are not pure virtual.
bool IReactToTriggerInterface::ReactToTrigger()
{
UE_LOG(LogTemp, Log, TEXT("IReactToTriggerInterface::ReactToTrigger()"));
return true;
}
void IReactToTriggerInterface::BumpTntoToTrigger_Implementation()
{
UE_LOG(LogTemp, Log, TEXT("IReactToTriggerInterface::BumpTntoToTrigger_Implementation()"));
}
3.然后用一个Actor类继承,并用各种方式重写。
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ReactToTriggerInterface.h"
#include "Trap.generated.h"
UCLASS()
class GWXPJ_API ATrap : public AActor,public IReactToTriggerInterface
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ATrap();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
//接口
virtual bool ReactToTrigger() override;
/* ---------------------------------------- */
/* ---------------------------------------- */
// 实现接口函数
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
bool SteppedToTrigger();
virtual bool SteppedToTrigger_Implementation() override;
/* ---------------------------------------- */
/* ---------------------------------------- */
// 实现接口函数
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
void BumpTntoToTrigger();
virtual void BumpTntoToTrigger_Implementation(); // 实现接口函数
/* ---------------------------------------- */
UPROPERTY(EditAnywhere)
UStaticMeshComponent* StMeshComponent;
};
#include "Trap.h"
// Sets default values
ATrap::ATrap()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
RootComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("RootComponent"));
StMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StMeshComponent"));
//RootComponent = StMeshComponent;
StMeshComponent->SetupAttachment(RootComponent);
}
// Called when the game starts or when spawned
void ATrap::BeginPlay()
{
Super::BeginPlay();
//C++ 里调用接口
ReactToTrigger(); // 调用纯C++接口
//SteppedToTrigger();
//SteppedToTrigger_Implementation();
BumpTntoToTrigger();
//Test_2(99);
this->Execute_TouchedToTrigger(this); // 调用接口,这个接口时纯蓝图接口,在蓝图中实现
this->Execute_SteppedToTrigger(this); // 调用接口,这个接口可以在蓝图中重写
//this->Execute_BumpTntoToTrigger(this); // 调用接口,这个接口可以在蓝图中重写
//this->Execute_Test_2(this, 99); // 调用接口,这个接口可以在蓝图中重写
}
// Called every frame
void ATrap::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
bool ATrap::ReactToTrigger()
{
UE_LOG(LogTemp, Log, TEXT("ATrap::ReactToTrigger()"));
return true;
}
bool ATrap::SteppedToTrigger_Implementation()
{
UE_LOG(LogTemp, Log, TEXT("ATrap::SteppedToTrigger_Implementation()"));
return true;
}
void ATrap::BumpTntoToTrigger_Implementation()
{
UE_LOG(LogTemp, Log, TEXT("ATrap::BumpTntoToTrigger_Implementation()"));
}
4.再通过测试是否实现接口,并调用接口
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TestInterfaceActor.generated.h"
UCLASS()
class GWXPJ_API ATestInterfaceActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ATestInterfaceActor();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// 测试 UE4 迭代器,接口,获取关卡内对象
UFUNCTION()
void CallInterface();
};
// Sets default values
ATestInterfaceActor::ATestInterfaceActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void ATestInterfaceActor::BeginPlay()
{
Super::BeginPlay();
CallInterface();
}
// Called every frame
void ATestInterfaceActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ATestInterfaceActor::CallInterface()
{
// UE4 迭代器TActorIterator
//TActorIterator<T> actorIt = TActorIterator<T>(GetWorld());
// 获取关卡里面所有的 ATrap 对象
TActorIterator<ATrap> actorIt = TActorIterator<ATrap>(GetWorld(), ATrap::StaticClass());
for (actorIt; actorIt; ++actorIt)
{
if (!actorIt)
{
continue;
}
ATrap* trap = *actorIt;
//判断ATrap类是否实现了 UReactToTriggerInterface 接口,这里传入 UReactToTriggerInterface 而非 IReactToTriggerInterface
bool isImplement = trap->GetClass()->ImplementsInterface(UReactToTriggerInterface::StaticClass());
if (isImplement)
{
// 转换为 IReactToTriggerInterface 接口
IReactToTriggerInterface* inter = Cast<IReactToTriggerInterface>(trap);
inter->Execute_TouchedToTrigger(trap); // 调用接口,这个接口时纯蓝图接口,只能在蓝图中实现
inter->Execute_SteppedToTrigger(trap); //调用接口,蓝图可覆盖接口
inter->Execute_BumpTntoToTrigger(trap); //调用接口,蓝图可覆盖接口
//inter->Execute_Test_2(trap, 99);//调用接口,蓝图可覆盖接口
inter->ReactToTrigger();//调用接口,纯C++接口
}
}
}
也可以继承自蓝图后,在蓝图里重写后调用