自定义事件分发

news2024/11/15 22:19:46

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

#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

#include "EventInterface.h"

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

#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

#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

#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

#include "MyData.h"
UMyData::UMyData()
{
}

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

#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

#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

#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、在蓝图中监听、接收、移除事件
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2110511.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

页面小组件-搜索栏(二)-未经项目验证,慎重!!!

前言说明 这一版是未经过项目验证的&#xff0c;可能会有地方需要自行调整&#xff0c;如需使用&#xff0c;请慎重、慎重、再慎重&#xff01;&#xff01;&#xff01; 前言追溯 前面分享过的搜索栏组件是一个临时产物&#xff0c;经历了一两个项目之后就被淘汰了。后续在…

Aloudata AIR :国内首个 Data Fabric 逻辑数据平台

AIR 的寓意是“极致轻盈的数据交付”&#xff1a;A - Adaptive 自适应&#xff0c;I - Integration 集成&#xff0c;R - Resilience 弹性 News&#xff1a;Aloudata AIR 发布 作为国内首个 Data Fabric 逻辑数据平台&#xff0c;Aloudata AIR 通过自研的数据虚拟化技术&#…

使用树莓派学习——Linux库编程

树莓派开发——Linux静态动态库 文章目录 树莓派开发——Linux静态动态库一、分文件编程1.1 分文件编程的优点&#xff1a;1.2 分文件编程的步骤&#xff1a; 二、Linux的库2.1 函数库的概念&#xff1a;2.2 静态库和动态库的比较&#xff1a;静态数据库&#xff08;libXXX.a&a…

奖项再+1!通义灵码智能编码助手通过可信 AI 智能编码工具评估,获当前最高等级

阿里云的通义灵码智能编码助手参与中国信通院组织的可信AI智能编码工具首轮评估&#xff0c;最终获得 4 级评级&#xff0c;成为国内首批通过该项评估并获得当前最高评级的企业之一。 此次评估以《智能化软件工程技术和应用要求 第 2 部分&#xff1a;智能开发能力》为依据&…

C/C++的自由落体运动

目录 1. 前言 2. 正文 2.1 问题 2.2 解决办法 2.2.1 思路 2.2.2 代码实现 2.2.3 测试结果 3. 备注 1. 前言 这个题目非常有意思&#xff0c;可以活跃自己的思维&#xff0c;毕竟代码来源于生活&#xff0c;又返回给生活。 2. 正文 2.1 问题 题目描述&#xff1a; …

携手共建云安全未来 |“集美大学服云实习基地”授牌仪式圆满举行

集美大学服云实习基地授牌仪式 9月3日&#xff0c;集美大学服云实习基地授牌仪式在厦门成功举行。集美大学科研处副处长茅剑、计算机工程学院副院长刘晋明&#xff0c;以及安全狗副总裁&CTO陈荣有、副总裁刘春辉共同出席此次的授牌仪式。 01 会上&#xff0c;安全狗副总裁刘…

梨花声音教育退费普通话学习技巧之了解文化背景

在学习普通话的过程中&#xff0c;了解中国的文化背景是不可或缺的一环。语言不仅是交流的工具&#xff0c;更是文化的载体。通过深入了解中国的历史、文化和社会背景&#xff0c;学习者可以更好地理解和掌握普通话&#xff0c;使语言学习变得更加生动有趣。本文将从几个方面详…

监控平台总结之面试常问答案

思路 延伸的面试题总结及答案&#xff1a; 1.说说前端监控平台/监控SDK架构设计和难点亮点&#xff1f; 架构设计 数据采集层: SDK: 在前端集成的 SDK 负责采集数据&#xff0c;包括性能指标、用户行为、错误日志等。 数据收集: 实现高效的数据采集机制&#xff0c;支持实时…

C++_多态详解

多态的概念 概念&#xff1a;需要去完成某个行为时&#xff0c;当 不同的对象去完成 会产生出不同的状态。通俗点说就是 不同类型的对象去做同一个行为&#xff0c;产生的结果不同。 多态的定义及实现 虚函数 定义&#xff1a;即被virtual修饰的类成员函数称为虚函数 虚函…

多门店管理下的高效IT运维策略与实战指南

连锁门店作为直接面向消费者的服务点&#xff0c;是企业与顾客建立联系的关键触点。随着商业竞争的加剧&#xff0c;连锁门店企业纷纷通过扩大实体店面的规模来抢占市场份额。随着门店数量的激增&#xff0c;门店IT运维管理的复杂性和挑战也日益凸显。本文将深入剖析门店IT运维…

828华为云征文|采用Flexus云服务器X实例部署RTSP直播服务器

一、前言 这篇文章讲解&#xff1a; 采用华为云最新推出的Flexus云服务器X实例搭建RTSP服务器&#xff0c;完成视频直播需求。 随着实时视频流传输需求的增长&#xff0c;RTSP&#xff08;实时流协议&#xff09;服务器成为了许多视频监控、直播和多媒体应用的核心组件。在当…

有趣的手机端见缝插针游戏源码

有趣的手机端见缝插针游戏源码下载&#xff0c;注&#xff1a;本地预览请用火狐浏览器模拟移动端&#xff0c;chrome本地预览存在跨域问题。 微信扫码获取源码

vue3 响应式 API:shallowRef()和shallowReactive()

shallowRef() shallowRef()是一个用于创建浅层响应式引用的函数。它创建一个响应式数据&#xff0c;但只对顶层属性进行响应式处理。 特点&#xff1a; 只跟踪引用值的变化&#xff0c;不关心值内部的属性变化。 <template><div>{{ shallowRefObj }}</div>…

LLM 模型压缩之三: FoldGPT

0. 资源链接 论文: FoldGPT: Simple and Effective Large Language Model Compression Scheme 项目: to be released. 1. 背景动机 现有的大语言模型推理存在以下问题&#xff1a; LLM 模型因为有大量的参数&#xff0c;以及 next token 的预测方式&#xff0c;导致 LLM 模…

关于vue项目启动报错Error: error:0308010C:digital envelope routines::unsupported

周五啦&#xff0c;总结一下这周遇到的个别问题吧&#xff0c;就是关于启动项目的时候其他的东西都准备好了&#xff0c;执行命令后报错Error: error:0308010C:digital envelope routines::unsupported 这里看一下我标注的地方&#xff0c;然后总结一下就不难发现问题所在 查看…

OBS怎么设置录制配置?3个电脑录屏小技巧妥妥教会你

OBS Studio是一款广受好评的开源录屏和直播软件&#xff0c;它以其强大的功能和用户友好的操作界面而闻名。对于初次接触OBS的用户来说&#xff0c;可能会对软件的众多按钮感到困惑。本文将为你提供一份简洁明了的OBS录屏指南&#xff0c;帮助你快速上手。 演示机型&#xff1a…

下载量10w+!LLM经典《大型语言模型:语言理解和生成》pdf分享

介绍 近年来&#xff0c;人工智能在新语言能力方面取得了显著进展&#xff0c;深度学习技术的快速发展推动了语言AI系统在文本编写和理解方面的表现。这一趋势催生了许多新功能、产品和整个行业的兴起。 本书旨在为Python开发者提供实用工具和概念&#xff0c;帮助他们利用预…

IP地址与MAC地址的区别:‌理解网络层与数据链路层的基石

在网络通信的广阔天地中&#xff0c;‌IP地址与MAC地址如同两座灯塔&#xff0c;‌各自照亮着不同的海域。‌它们虽然都扮演着标识网络设备的重要角色&#xff0c;‌但却在网络的不同层次上发挥着作用。‌本文将带您走进IP地址与MAC地址的世界&#xff0c;‌简述MAC与IP地址的区…

在SOLIDWORKS中高效转换:从实体模型到钣金件的设计优化

在设计生产中&#xff0c;当我们收到中间格式的模型文件时&#xff0c;并希望将其转换为钣金件以进一步加工生产&#xff0c;该怎么做呢&#xff1f; 利用SOLIDWORKS软件&#xff0c;可以直接将实体模型转换为钣金件&#xff0c;来完成后续的设计。 中性文件 钣金件 一、设置…

万象奥科参展“2024 STM32全国巡回研讨会”—深圳站、广州站

9月3日-9月5日&#xff0c;万象奥科参展“2024 STM32全国巡回研讨会”— 深圳站、广州站。此次STM32研讨会将会走进全国11个城市&#xff0c;展示STM32在智能工业、无线连接、边缘人工智能、安全、图形用户界面等领域的产品解决方案及多样化应用实例&#xff0c;深入解读最新的…