BlueprintNativeEvent
这个参数:会在C++中提供一个默认的实现,然后蓝图中去覆盖它改写它,在蓝图中实现这个函数时,如果调用一个父类的版本,它会先调用C++里面加了_Implementation
这个函数,然后再去做蓝图其他的操作// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "EventInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UEventInterface : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class DISTRIBUTE_API IEventInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
UFUNCTION(BlueprintNativeEvent,Category="Event Dispather Tool")
void OnReceiveEvent(UObject* Data);
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "EventInterface.h"
// Add default functionality here for any IEventInterface functions that are not pure virtual.
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "EventManager.generated.h"
/**
*
*/
UCLASS()
class DISTRIBUTE_API UEventManager : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
private:
//监听者
static TMap<FString, TArray<UObject*>> AllListeners;
public:
UFUNCTION(BlueprintCallable, Category = "Event Dispather Tool")
static void AddEventListener(FString EventName, UObject* Listener);
UFUNCTION(BlueprintCallable, Category = "Event Dispather Tool")
static void RemoveEventListener(FString EventName, UObject* Listener);
UFUNCTION(BlueprintCallable, Category = "Event Dispather Tool")
static FString DispatchEvent(FString EventName, UObject* Data);
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Event Dispather Tool")
static UObject* NameAsset(UClass* ClassType);
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "EventManager.h"
void UEventManager::AddEventListener(FString EventName, UObject* Listener)
{
}
void UEventManager::RemoveEventListener(FString EventName, UObject* Listener)
{
}
FString UEventManager::DispatchEvent(FString EventName, UObject* Data)
{
return FString();
}
UObject* UEventManager::NameAsset(UClass* ClassType)
{
return nullptr;
}
加入接口的头文件,判断添加进来的事件名字是否为空,监听指针是否为空,检测对象是否有效,是否实现了指定的接口类
Listener->IsValidLowLevel()
:检查对象是否有效
Listener->GetClass()->ImplementsInterface(UEventInterface::StaticClass())
:检测接口是否实现指定接口,这里传入的UEventInterface
就是接口类中的参与蓝图的类名
//初始化监听器
TMap<FString, TArray<UObject*>> UEventManager::AllListeners;
void UEventManager::AddEventListener(FString EventName, UObject* Listener)
{
if (EventName == "" || Listener == nullptr || !Listener->IsValidLowLevel() ||
!Listener->GetClass()->ImplementsInterface(UEventInterface::StaticClass()))
{
return;
}
}
然后查找是否存在这个事件数组,如果为空说明目前没有这个事件,就重新添加一下,存在就直接添加事件进入到数组即可
AddEventListener函数完整代码逻辑
#include "EventManager.h"
#include "EventInterface.h"
//初始化监听器
TMap<FString, TArray<UObject*>> UEventManager::AllListeners;
void UEventManager::AddEventListener(FString EventName, UObject* Listener)
{
if (EventName == "" || Listener == nullptr || !Listener->IsValidLowLevel() ||
!Listener->GetClass()->ImplementsInterface(UEventInterface::StaticClass()))
{
return;
}
//查找是否存在这个事件数组
TArray<UObject*>* EventArr = UEventManager::AllListeners.Find(EventName);
//如果为空说明目前没有这个事件,就重新添加一下
if (EventArr == nullptr || EventArr->Num() == 0)
{
TArray<UObject*> NewEventArr = { Listener };
UEventManager::AllListeners.Add(EventName, NewEventArr);
}
//存在就直接添加事件进入到数组即可
else
{
EventArr->Add(Listener);
}
}
void UEventManager::RemoveEventListener(FString EventName, UObject* Listener)
{
TArray<UObject*>* EventArr = UEventManager::AllListeners.Find(EventName);
if (EventArr != nullptr && EventArr->Num() != 0)
{
EventArr->Remove(Listener);
}
}
FString UEventManager::DispatchEvent(FString EventName, UObject* Data)
{
TArray<UObject*>* EventArr = UEventManager::AllListeners.Find(EventName);
//如果不存在此事件数组
if (EventArr == nullptr || EventArr->Num() == 0)
{
return "'" + EventName + "'No Listener.";
}
//使用UE_LOG换行,方便查看
FString ErrorInfo = "\n";
for (int i = 0; i < EventArr->Num(); i++)
{
UObject* Obj = (*EventArr)[i];
//安全判断一下事件是否存在
if (Obj == nullptr || !Obj->IsValidLowLevel() || !Obj->GetClass()->ImplementsInterface(UEventInterface::StaticClass()))
{
//不存在直接剔除
EventArr->RemoveAt(i);
//剔除后要i--,因为TArray删除一个元素后会自动补齐,这样会导致我们当前循环出现bug
i--;
}
//通过了安全检测就直接派遣事件通知
else
{
UFunction* FUN = Obj->FindFunction("OnReceiveEvent");
//安全检测这个FUN是否有效
if (FUN == nullptr || !FUN->IsValidLowLevel())
{
//打印错误信息
ErrorInfo += "'" + Obj->GetName() + "'No 'OnReceiveEvent' Function.\n";
}
else
{
//调用
Obj->ProcessEvent(FUN, &Data);
}
}
}
return ErrorInfo;
}
NewObject(GetTransientPackage(), ClassType)
;
GetTransientPackage()
:返回一个临时包(主要用于对象池)的指针ClassType
:ClassType 是一个 UClass 指针,指定了新对象的类型。UObject* UEventManager::NameAsset(UClass* ClassType)
{
UObject* Obj = NewObject<UObject>(GetTransientPackage(), ClassType);
return Obj;
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "EventManager.h"
#include "EventInterface.h"
#include "Engine.h"
//初始化监听器
TMap<FString, TArray<UObject*>> UEventManager::AllListeners;
void UEventManager::AddEventListener(FString EventName, UObject* Listener)
{
if (EventName == "" || Listener == nullptr || !Listener->IsValidLowLevel() ||
!Listener->GetClass()->ImplementsInterface(UEventInterface::StaticClass()))
{
return;
}
//查找是否存在这个事件数组
TArray<UObject*>* EventArr = UEventManager::AllListeners.Find(EventName);
//如果为空说明目前没有这个事件,就重新添加一下
if (EventArr == nullptr || EventArr->Num() == 0)
{
TArray<UObject*> NewEventArr = { Listener };
UEventManager::AllListeners.Add(EventName, NewEventArr);
}
//存在就直接添加事件进入到数组即可
else
{
EventArr->Add(Listener);
}
}
void UEventManager::RemoveEventListener(FString EventName, UObject* Listener)
{
TArray<UObject*>* EventArr = UEventManager::AllListeners.Find(EventName);
if (EventArr != nullptr && EventArr->Num() != 0)
{
EventArr->Remove(Listener);
}
}
FString UEventManager::DispatchEvent(FString EventName, UObject* Data)
{
TArray<UObject*>* EventArr = UEventManager::AllListeners.Find(EventName);
//如果不存在此事件数组
if (EventArr == nullptr || EventArr->Num() == 0)
{
return "'" + EventName + "'No Listener.";
}
//使用UE_LOG换行,方便查看
FString ErrorInfo = "\n";
for (int i = 0; i < EventArr->Num(); i++)
{
UObject* Obj = (*EventArr)[i];
//安全判断一下事件是否存在
if (Obj == nullptr || !Obj->IsValidLowLevel() || !Obj->GetClass()->ImplementsInterface(UEventInterface::StaticClass()))
{
//不存在直接剔除
EventArr->RemoveAt(i);
//剔除后要i--,因为TArray删除一个元素后会自动补齐,这样会导致我们当前循环出现bug
i--;
}
//通过了安全检测就直接派遣事件通知
else
{
UFunction* FUN = Obj->FindFunction("OnReceiveEvent");
//安全检测这个FUN是否有效
if (FUN == nullptr || !FUN->IsValidLowLevel())
{
//打印错误信息
ErrorInfo += "'" + Obj->GetName() + "'No 'OnReceiveEvent' Function.\n";
}
else
{
//调用
Obj->ProcessEvent(FUN, &Data);
}
}
}
return ErrorInfo;
}
UObject* UEventManager::NameAsset(UClass* ClassType)
{
UObject* Obj = NewObject<UObject>(GetTransientPackage(), ClassType);
return Obj;
}
// Called when the game starts or when spawned
void AMyBPAndCpp_Sender::BeginPlay()
{
Super::BeginPlay();
FTimerHandle TimerHandle;
auto Lambda = []()
{
//开始广播事件
UMyData* Data = Cast<UMyData>(UEventManager::NameAsset(UMyData::StaticClass()));
Data->Param = FMath::RandRange(0, 100);
//委派事件
UEventManager::DispatchEvent("MyBPAndCpp_DispatchEvent", Data);
};
GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateLambda(Lambda), 3.f, true);
}
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyBPAndCpp_Sender.generated.h"
UCLASS()
class DISTRIBUTE_API AMyBPAndCpp_Sender : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AMyBPAndCpp_Sender();
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Properties")
class UStaticMeshComponent* StaticMesh;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyBPAndCpp_Sender.h"
#include "Components/StaticMeshComponent.h"
#include "UObject/ConstructorHelpers.h"
#include "EventDistributeTool/EventManager.h"
#include "Public/TimerManager.h"
#include "MyData.h"
// Sets default values
AMyBPAndCpp_Sender::AMyBPAndCpp_Sender()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
RootComponent = StaticMesh;
static ConstructorHelpers::FObjectFinder<UStaticMesh> StaticMeshAsset(TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'"));
static ConstructorHelpers::FObjectFinder<UMaterialInterface> MaterialAsset(TEXT("Material'/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial'"));
if (StaticMeshAsset.Succeeded() && MaterialAsset.Succeeded())
{
StaticMesh->SetStaticMesh(StaticMeshAsset.Object);
StaticMesh->SetMaterial(0, MaterialAsset.Object);
}
}
// Called when the game starts or when spawned
void AMyBPAndCpp_Sender::BeginPlay()
{
Super::BeginPlay();
FTimerHandle TimerHandle;
auto Lambda = []()
{
//开始广播事件
UMyData* Data = Cast<UMyData>(UEventManager::NameAsset(UMyData::StaticClass()));
Data->Param = FMath::RandRange(0, 100);
//委派事件
UEventManager::DispatchEvent("MyBPAndCpp_DispatchEvent", Data);
};
GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateLambda(Lambda), 3.f, true);
}
// Called every frame
void AMyBPAndCpp_Sender::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void AMyBPAndCpp_Sender::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
BlueprintNativeEvent
反射参数,所以在这实现加后缀_Implementation
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "EventDistributeTool/EventInterface.h"
#include "BPAndCpp/Actor_Receive.h"
#include "Actor_Receive_R.generated.h"
/**
*
*/
UCLASS()
class DISTRIBUTE_API AActor_Receive_R : public AActor_Receive, public IEventInterface
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
public:
virtual void OnReceiveEvent_Implementation(UObject* Data) override;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "Actor_Receive_R.h"
#include "Engine/Engine.h"
#include "MyData.h"
#include "EventDistributeTool/EventManager.h"
void AActor_Receive_R::BeginPlay()
{
Super::BeginPlay();
//订阅事件
UEventManager::AddEventListener("MyBPAndCpp_DispatchEvent", this);
}
void AActor_Receive_R::OnReceiveEvent_Implementation(UObject* Data)
{
//打印到屏幕
GEngine->AddOnScreenDebugMessage(INDEX_NONE, 10.f, FColor::Red, FString::Printf(TEXT("%i"), Cast<UMyData>(Data)->Param));
}