当前位置: 首页 > news >正文

自定义事件分发

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

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Linux(驱动中) 时间管理和内核定时器(学习总结)
  • Ollama—87.4k star 的开源大模型服务框架!!
  • Linux驱动.之驱动开发思维,设备,驱动,总线分析思想,驱动的分类(字符设备,块设备,网络设备)
  • 降低安全违规行为发生率,节省人工监管成本的智慧园区开源了
  • iOS面试:如何手动触发一个value的KVO?
  • Qt-桌面服务和托盘
  • GPU环境配置:1.CUDA、Anaconda、Pytorch
  • 备份还原 本地所有的Docker 镜像并且在另一台机器上还原
  • bios中启动模式uefi是什么意思_uefi相关知识史上最全介绍
  • 超声波测距模块HC-SR04(基于STM32F103C8T6HAL库)
  • [米联客-XILINX-H3_CZ08_7100] FPGA程序设计基础实验连载-39 HDMI视频输入测试
  • 我司使用了两年的高效日志打印工具,非常牛逼!
  • 【C++】优化函数对象:提升性能和内存效率
  • 第十六篇:走入计算机网络的传输层--传输层概述
  • 【Linux 运维知识】Linux 编译后的内核镜像大小
  • php的引用
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • Android 控件背景颜色处理
  • CSS魔法堂:Absolute Positioning就这个样
  • Linux下的乱码问题
  • mysql外键的使用
  • React的组件模式
  • redis学习笔记(三):列表、集合、有序集合
  • vue 配置sass、scss全局变量
  • Wamp集成环境 添加PHP的新版本
  • WebSocket使用
  • 爱情 北京女病人
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 分享几个不错的工具
  • 爬虫进阶 -- 神级程序员:让你的爬虫就像人类的用户行为!
  • 如何优雅地使用 Sublime Text
  • 使用Swoole加速Laravel(正式环境中)
  • 数据仓库的几种建模方法
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • #FPGA(基础知识)
  • #pragma once
  • #pragma once与条件编译
  • #QT 笔记一
  • (06)金属布线——为半导体注入生命的连接
  • (Ruby)Ubuntu12.04安装Rails环境
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (四)c52学习之旅-流水LED灯
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • (转)fock函数详解
  • **python多态
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .NET Reactor简单使用教程
  • .net Stream篇(六)
  • .Net程序帮助文档制作
  • .one4-V-XXXXXXXX勒索病毒数据怎么处理|数据解密恢复
  • ??在JSP中,java和JavaScript如何交互?