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

UE 事件分发机制 day9

观察者模式原理

  • 观察者模式通常有观察者与被观察者,当被观察者状态发生改变时,它会通知所有的被观察者对象,使他们能够及时做出响应,所以也被称作“发布-订阅模式”。总得来说就是你关注了一个主播,主播的状态改变会通知这些人,关注主播的这些人都会根据主播的通知改变一些状态

观察者模式游戏工程案例(击杀怪物后的逻辑)

  • 观察者模式定义了对象之间的一对多关系,当主题对象改变状态发出通知的时候,它的所有观察者都会收到提示然后作出自己的响应
    在这里插入图片描述

事件分发机制定义

  • 通过观察者模式的“订阅-发布”机制使用事件传递数据驱动行为的方法
    在这里插入图片描述
  • 优点:
    • 解耦合
    • 可读性强
    • 模块独立化高
    • 可自行测试

虚幻中的内置事件分发机制

纯蓝图广播事件通知

  • 创建一个Pawn蓝图类,开个定时器,让这个Pawn每三秒发送一下事件,添加一个事件调度器,在定时器中进行广播通知
    在这里插入图片描述
    在这里插入图片描述

纯蓝图订阅事件通知

  • 新建一个Actor,然后派生出三个子类去订阅广播的事件进行打印
    在这里插入图片描述
  • 运行结果
    在这里插入图片描述

纯蓝图解绑订阅事件通知

  • 可以在发布者中终止所有订阅通知
    在这里插入图片描述
  • 运行结果,这样就只会输出一次三色打印数字,因为四秒后就结束所有订阅者的订阅
    在这里插入图片描述
  • 也可以订阅者自己解绑
    在这里插入图片描述
  • 运行结果,这样后面就不会有这个订阅者的打印了
    在这里插入图片描述

纯Cpp之多播委托

  • 创建一个新Mode用来使用Cpp,创建一个C++的Pawn类,默认硬编码静态网格与材质
  • 硬编码网格与材质
	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);}

在这里插入图片描述
在这里插入图片描述

  • 运行结果
    在这里插入图片描述

纯Cpp之多播委托的广播事件通知

  • DECLARE_MULTICAST_DELEGATE_OneParam:用于声明一个多播委托。多播委托是一种特殊的委托,它可以同时注册多个监听器,当委托被调用时,所有的监听器都会收到通知并执行相关的方法。
    • DECLARE_MULTICAST_DELEGATE_OneParam(FMyDelegate, float);:声明了一个名为 FMyDelegate 的多播委托,它可以接受一个浮点数作为参数。
    • OneParam表示这个多播委托有一个参数,可以传入一个参数给监听器。
    • OnParam这里可以写0-9,表示传入的参数个数,例如TwoParam,就表示传两个参数
  • 注意切换Mode的Default Pawn Class小心莫名报错
  • 声明一个参数的多播委托对象
	//声明一个名为 FCpp_Broadcast 的多播委托,它可以接受一个整数作为参数。DECLARE_MULTICAST_DELEGATE_OneParam(FCpp_Broadcast,int)FCpp_Broadcast Cpp_Broadcast;
  • 编写多播委托广播
// Called when the game starts or when spawned
void ACppSender_Pawn::BeginPlay()
{Super::BeginPlay();FTimerHandle TimerHandle;auto Lambda = [this](FCpp_Broadcast* CB){CB->Broadcast(FMath::RandRange(0, 100));};//开启定时器,每3秒发一次广播GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateLambda(Lambda, &Cpp_Broadcast), 3.f, true);
}
  • 运行结果,相当与上面的蓝图创建广播事件通知

纯Cpp之多播委托的订阅事件通知

  • 新建一个Actor基类然后派生出三个子类进行订阅事件
  • Actor基类就只需要硬编码静态网格与材质
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Properties")class UStaticMeshComponent* StaticMesh;
//--------------------------------------------------------------------------
ACppReceiveActor::ACppReceiveActor()
{// 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;StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));RootComponent = StaticMesh;ConstructorHelpers::FObjectFinder<UStaticMesh> StaticMeshAsset(TEXT("StaticMesh'/Engine/BasicShapes/Cube.Cube'"));ConstructorHelpers::FObjectFinder<UMaterialInterface> MaterialAsset(TEXT("Material'/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial'"));if (StaticMeshAsset.Succeeded() && MaterialAsset.Succeeded()){StaticMesh->SetStaticMesh(StaticMeshAsset.Object);StaticMesh->SetMaterial(0, MaterialAsset.Object);}}
  • Actor的三个子类去接受广播进行屏幕打印数字,声明一个函数用来打印数字

CppReceiveActor_R.h

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "UE_Cpp/CppReceiveActor.h"
#include "CppReceiveActor_R.generated.h"/*** */
UCLASS()
class DISTRIBUTE_API ACppReceiveActor_R : public ACppReceiveActor
{GENERATED_BODY()
public:void OnReceive(int Param);
protected:virtual void BeginPlay() override;
};

CppReceiveActor_R.cpp

  • AddOnScreenDebugMessage 是虚幻中的一种功能,它可以在屏幕上显示一条调试消息。这对于开发人员在调试过程中非常有用,可以帮助他们快速了解当前程序的状态和进度。
    具体来说,AddOnScreenDebugMessage 函数的使用方式如下:
    GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("This is a debug message"));
    
    这个函数的第一个参数表示消息 ID,用于区分不同的消息。第二个参数表示 消息的显示时间,单位是秒。第三个参数表示消息的颜色,第四个参数表示消息的内容。需要注意的是,AddOnScreenDebugMessage 函数并不是一个标准库函数,而是 Unreal Engine 中的一个全局函数,所以使用前需要先引入相关的头文件:#include "Engine/Engine.h"
// Fill out your copyright notice in the Description page of Project Settings.#include "CppReceiveActor_R.h"
#include "Kismet/GameplayStatics.h"
#include "CppSender_Pawn.h"
#include "Engine/Engine.h"void ACppReceiveActor_R::BeginPlay()
{Super::BeginPlay();//获取到CppSender_PawnACppSender_Pawn* PlayerPawn = Cast<ACppSender_Pawn>(UGameplayStatics::GetPlayerPawn(this, 0));//订阅事件通知PlayerPawn->Cpp_Broadcast.AddUObject(this, &ACppReceiveActor_R::OnReceive);
}void ACppReceiveActor_R::OnReceive(int Param)
{//打印到屏幕GEngine->AddOnScreenDebugMessage(INDEX_NONE, 10.f, FColor::Red, FString::Printf(TEXT("%i"), Param));
}

纯Cpp之多播委托的解绑订阅事件通知

  • Cpp中订阅事件通知,会返回一个FDelegate句柄,我们接受这个句柄然后调用Remove删除即可,也可以使用RemoveAll也是一样的效果,但是RemoveAll使用方法不一样
void ACppReceiveActor_R::BeginPlay()
{Super::BeginPlay();//获取到CppSender_PawnACppSender_Pawn* PlayerPawn = Cast<ACppSender_Pawn>(UGameplayStatics::GetPlayerPawn(this, 0));//订阅事件通知FDelegateHandle DelegateHandle = PlayerPawn->Cpp_Broadcast.AddUObject(this, &ACppReceiveActor_R::OnReceive);FTimerHandle TimerHandle;auto Lambda = [=](){PlayerPawn->Cpp_Broadcast.Remove(DelegateHandle);//删除所有订阅者,一般在发布者使用//PlayerPawn->Cpp_Broadcast.Clear();};GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateLambda(Lambda), 4.f, false);
}
  • 运行结果
    在这里插入图片描述
  • 删除所有订阅者
    在这里插入图片描述

蓝图与Cpp混合多播动态委托的广播事件通知

  • 多播委托可以蓝图与Cpp混合使用,新建一个Pawn类来创建广播事件
  • DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam:使用这个宏就可以定义一个可以在蓝图中调用的多播委托,多加了一个DYNAMIC就可以被蓝图去识别到了
  • 创建多播委托代理,要加上反射,参数为BlueprintAssignable这样就可以被蓝图调用
public:// Sets default values for this pawn's propertiesABPAndCpp_Sender();
//注意这里要加分号,上个没有加DYNAMIC的不用加分号DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBPAndCpp_Broadcast, int, Param);UPROPERTY(BlueprintAssignable)FBPAndCpp_Broadcast BPAndCpp_Broadcast;UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="Properties")class UStaticMeshComponent* StaticMesh;
void ABPAndCpp_Sender::BeginPlay()
{Super::BeginPlay();FTimerHandle TimerHandle;auto Lambda = [](FBPAndCpp_Broadcast* BPAC){BPAC->Broadcast(FMath::RandRange(0, 100));};GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateLambda(Lambda,&BPAndCpp_Broadcast), 3.f, true);}

蓝图与Cpp混合多播动态委托的订阅事件通知

  • 创建一个基类Actor派生出三个子类进行订阅事件
  • 注意这里的接收函数需要添加反射,反射可以无参数
  • 注意这里的绑定使用的是AddDynamic而不是AddUObject
void ABPAndCpp_Receive_R::BeginPlay()
{Super::BeginPlay();ABPAndCpp_Sender* MainPlayer = Cast<ABPAndCpp_Sender>(UGameplayStatics::GetPlayerPawn(this, 0));//绑定订阅事件通知MainPlayer->BPAndCpp_Broadcast.AddDynamic(this, &ABPAndCpp_Receive_R::OnReceived);
}void ABPAndCpp_Receive_R::OnReceived(int Param)
{GEngine->AddOnScreenDebugMessage(INDEX_NONE, 10.f, FColor::Red, FString::Printf(TEXT("%i"), Param));
}
  • 运行结果,此时C++拉入场景中也可以调用通知
    在这里插入图片描述

蓝图与Cpp混合多播动态委托的蓝图多播动态委托订阅

  • 新建一个Actor蓝图,派生三个蓝图,在蓝图中就可以调用多播委托,因为有反射,会出现一个委托
    在这里插入图片描述
    在这里插入图片描述
  • 运行结果
    在这里插入图片描述
  • 蓝图中的解绑和之前纯蓝图解绑事件还是一样的
  • C++中解绑使用RemoveDynamic就行
    在这里插入图片描述
  • 运行结果
    在这里插入图片描述

相关文章:

  • “SRP模型+”多技术融合在生态环境脆弱性评价模型构建、时空格局演变分析与RSEI 指数的生态质量评价及拓展应用
  • vue中:计算属性computed
  • oracle rac环境归档日志清除
  • fiddler设置过滤你就这样做,一做一个不只声!
  • 智能优化算法应用:基于教与学算法无线传感器网络(WSN)覆盖优化 - 附代码
  • 进程、线程以及进程与线程的区别
  • 物理机虚拟化关键技术介绍
  • 如何使用企业微信 WorkTool API 开源框架快速开发企微聊天机器人(详细教程)
  • 采用NTC进行温度测量典型电路
  • docker介绍
  • C语言——打印出所有的“水仙花数”
  • HarmonyOS(四)—— 如何创建自定义组件
  • JSON.stringify,JSON.parse
  • OPENWRT解决配置pppoe后无法光猫路由管理界面
  • YOLOv5全网独家改进:NanoDet算法动态标签分配策略(附原创改进代码),公开数据集mAP有效涨点,来打造新颖YOLOv5检测器
  • 【刷算法】从上往下打印二叉树
  • 0x05 Python数据分析,Anaconda八斩刀
  • Apache Pulsar 2.1 重磅发布
  • CentOS6 编译安装 redis-3.2.3
  • express.js的介绍及使用
  • hadoop入门学习教程--DKHadoop完整安装步骤
  • Leetcode 27 Remove Element
  • LeetCode29.两数相除 JavaScript
  • mysql_config not found
  • mysql外键的使用
  • node.js
  • 记一次用 NodeJs 实现模拟登录的思路
  • 设计模式走一遍---观察者模式
  • 使用 @font-face
  • RDS-Mysql 物理备份恢复到本地数据库上
  • (11)MATLAB PCA+SVM 人脸识别
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (笔试题)合法字符串
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (九)c52学习之旅-定时器
  • (论文阅读40-45)图像描述1
  • (四)汇编语言——简单程序
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  • .net refrector
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
  • .net6+aspose.words导出word并转pdf
  • .netcore 如何获取系统中所有session_ASP.NET Core如何解决分布式Session一致性问题
  • .NET处理HTTP请求
  • .NET项目中存在多个web.config文件时的加载顺序
  • .NET中的十进制浮点类型,徐汇区网站设计
  • /usr/bin/env: node: No such file or directory
  • @KafkaListener注解详解(一)| 常用参数详解
  • [ 蓝桥杯Web真题 ]-Markdown 文档解析
  • [1204 寻找子串位置] 解题报告