自定义事件分发

一、在C++中创建可接收事件的接口类EventInterface,继承自UInterface

1、EventInterface.h

cpp 复制代码
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "EventInterface.generated.h"
UINTERFACE(MinimalAPI)
class UEventInterface : public UInterface
{
	GENERATED_BODY()
};

class EVENTDISPATHER_API IEventInterface
{
	GENERATED_BODY()
public:
	UFUNCTION(BlueprintNativeEvent, Category = "Event Dispather Utility")
	void OnReceiveEvent(UObject* Data);
};

注意:

声明一个接收事件的函数OnReceiveEvent,这里没有用Virtual关键字,是因为Virtual关键字不能在蓝图中使用。

BlueprintNativeEvent标记的函数,在C++中需要通过OnReceiveEvent_Implement来实现,在蓝图中也可以调出OnReceiveEvent事件节点。

蓝图中如果调用父类的OnReceiveEvent函数,就是先调用C++版本的OnReceiveEvent_Implement函数。

2、EventInterface.cpp

cpp 复制代码
#include "EventInterface.h"

二、在C++中创建事件管理器类CustomEventManager,继承自BlueprintFunctionLibrary

1、CustomEventManager.h

cpp 复制代码
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "CustomEventManager.generated.h"
UCLASS()
class EVENTDISPATHER_API UCustomEventManager : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
private:
	static TMap<FString, TArray<UObject*>> AllListeners;
public:
	UFUNCTION(BlueprintCallable, Category = "Event Dispather Utility")
	static void AddEventListener(FString EventName, UObject* Listener);
	UFUNCTION(BlueprintCallable, Category = "Event Dispather Utility")
	static void RemoveEventListener(FString EventName, UObject* Listener);
	UFUNCTION(BlueprintCallable, Category = "Event Dispather Utility")
	static FString DispatchEvent(FString EventName, UObject* Data);
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Event Dispather Utility")
	static UObject* NewAsset(UClass* ClassType);
};

注意:事件管理器包含了下面函数

添加事件监听AddEventListener

移除事件监听RemoveEventListener

发送事件DispatchEvent

初始化事件参数NewAsset

2、CustomEventManager.cpp

cpp 复制代码
#include "CustomEventManager.h"
#include "EventInterface.h"
#include "Engine.h"

TMap<FString, TArray<UObject*>> UCustomEventManager::AllListeners;

void UCustomEventManager::AddEventListener(FString EventName, UObject* Listener)
{
	//表示指针为nullptr但是可能还没有被垃圾回收
	//所以需要IsValidLowLevel判断底层是否有效
	//ImplementsInterface用于判断是否实现了指定的接口
	if (EventName == "" || Listener == nullptr || !Listener->IsValidLowLevel() || !Listener->GetClass()->ImplementsInterface(UEventInterface::StaticClass()))
	{
		return;
	}

	TArray<UObject*>* Arr = UCustomEventManager::AllListeners.Find(EventName);

	if (Arr == nullptr || Arr->Num() == 0)
	{
		TArray<UObject*> NewArr = { Listener };
		UCustomEventManager::AllListeners.Add(EventName, NewArr);
	}
	else
	{
		Arr->Add(Listener);
	}
}

void UCustomEventManager::RemoveEventListener(FString EventName, UObject* Listener)
{
	TArray<UObject*>* Arr = UCustomEventManager::AllListeners.Find(EventName);

	if (Arr != nullptr && Arr->Num() != 0)
	{
		Arr->Remove(Listener);
	}
}

FString UCustomEventManager::DispatchEvent(FString EventName, UObject* Data)
{
	TArray<UObject*>* Arr = UCustomEventManager::AllListeners.Find(EventName);

	if (Arr == nullptr || Arr->Num() == 0)
	{
		return "'" + EventName + "' No Listener.";
	}

	FString ErrorInfo = "\n";

	for (int i = 0; i < Arr->Num(); i++)
	{
		UObject* Obj = (*Arr)[i];
		if (Obj == nullptr || !Obj->IsValidLowLevel() || !Obj->GetClass()->ImplementsInterface(UEventInterface::StaticClass()))
		{
			Arr->RemoveAt(i--);
		}
		else
		{
			UFunction* Fun = Obj->FindFunction("OnReceiveEvent");
			if (Fun == nullptr || !Fun->IsValidLowLevel())
			{
				ErrorInfo += "'" + Obj->GetName() + "' No 'OnReceiveEvent' Function. \n";
			}
			else
			{
				Obj->ProcessEvent(Fun, &Data);
			}
		}
	}
	return ErrorInfo;
}
UObject* UCustomEventManager::NewAsset(UClass* ClassType)
{
	//GetTransientPackage获取临时的包,将Obj生成进去
	UObject* Obj = NewObject<UObject>(GetTransientPackage(), ClassType);
	return Obj;
}

三、在C++中创建事件参数类MyData,继承自UObject

1、MyData.h

cpp 复制代码
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "MyData.generated.h"
UCLASS(Blueprintable)
class EVENTDISPATHER_API UMyData : public UObject
{
	GENERATED_BODY()
public:
	UMyData();
	UPROPERTY(BlueprintReadWrite)
	int Param;
};

2、MyData.cpp

cpp 复制代码
#include "MyData.h"
UMyData::UMyData()
{
}

四、在C++中发送、接收和移除事件

1、发送事件

cpp 复制代码
#include "../EventDispatherUtility/CustomEventManager.h"
#include "MyData.h"
void AMyBpAndCpp_Sender::BeginPlay()
{
	UMyData* Data = Cast<UMyData>(UCustomEventManager::NewAsset(UMyData::StaticClass()));
	Data->Param = FMath::RandRange(0, 100);
	UCustomEventManager::DispatchEvent("MyBpAndCpp_DispatchEvent", Data);
}

2、接收和移除事件

MyBpAndCpp_Receive_G.h

cpp 复制代码
#pragma once
#include "CoreMinimal.h"
#include "MyBpAndCpp_Receive_Parent.h"
#include "../EventDispatherUtility/EventInterface.h"
#include "MyBpAndCpp_Receive_G.generated.h"
UCLASS()
class EVENTDISPATHER_API AMyBpAndCpp_Receive_G : public AMyBpAndCpp_Receive_Parent,public IEventInterface
{
	GENERATED_BODY()
protected:
	virtual void BeginPlay() override;
	virtual void BeginDestroy() override;
public:
	void OnReceiveEvent_Implementation(UObject* Data) override;
};

MyBpAndCpp_Receive_G.cpp

cpp 复制代码
#include "MyBpAndCpp_Receive_G.h"
#include "Engine/Engine.h"
#include "MyData.h"
#include "../EventDispatherUtility/CustomEventManager.h"
#include "TimerManager.h"

void AMyBpAndCpp_Receive_G::BeginPlay()
{
	Super::BeginPlay();
	UCustomEventManager::AddEventListener("MyBpAndCpp_DispatchEvent", this);

	FTimerHandle TimerHandle;
	auto Lambda = [this]()
		{
			UCustomEventManager::RemoveEventListener("MyBpAndCpp_DispatchEvent", this);
		};
	//GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateLambda(Lambda), 5.0f, false);

}
void AMyBpAndCpp_Receive_G::BeginDestroy()
{
	UCustomEventManager::RemoveEventListener("MyBpAndCpp_DispatchEvent", this);

	Super::BeginDestroy();
}
void AMyBpAndCpp_Receive_G::OnReceiveEvent_Implementation(UObject* Data)
{
	GEngine->AddOnScreenDebugMessage(INDEX_NONE, 10.0f, FColor::Green, FString::Printf(TEXT("%i"), Cast<UMyData>(Data)->Param));
}

五、在C++中发送事件,在蓝图中监听、接收、移除事件

1、C++发送事件同上

2、在蓝图中监听、接收、移除事件

六、在蓝图中发送、监听、接收、移除事件,

1、在蓝图中发送事件

2、在蓝图中监听、接收、移除事件

相关推荐
不爱说话的采儿3 小时前
UE5详细保姆教程(第四章)
笔记·ue5·游戏引擎·课程设计
二DUAN帝3 小时前
UE实现路径回放、自动驾驶功能简记
人工智能·websocket·机器学习·ue5·自动驾驶·ue4·cesiumforue
温玉琳琅9 小时前
【UE5】虚幻引擎小百科
ue5·游戏引擎·虚幻
远离UE41 天前
UE 材质 变体 概念
ue5·材质
吴梓穆3 天前
UE5 重新编译插件版本
ue5
HECUgauss3 天前
UE5 使用过程遇到的问题
ue5
小白学过的代码3 天前
ue5.4和webul通信
开发语言·javascript·ue5
m0_552200823 天前
《UE5_C++多人TPS完整教程》学习笔记40 ——《P41 装备(武器)姿势(Equipped Pose)》
c++·游戏·ue5
漫游者Nova4 天前
虚幻引擎Unreal Engine5恐怖游戏设计制作教程,从入门到精通从零开始完整项目开发实战详细讲解中英字幕
ue5·游戏引擎·虚幻·游戏开发完整教程·恐怖游戏开发
ue星空5 天前
UE5音频技术
ue5