学习虚幻C++开发日志——委托(持续更新中)

委托

官方文档:Delegates and Lamba Functions in Unreal Engine | 虚幻引擎 5.5 文档 | Epic Developer Community | Epic Developer Community

简单地说,委托就像是一个“函数指针”,但它更加安全和灵活。它允许程序在运行时动态地调用不同的函数。

(1)解耦对象间的关联

委托允许对象之间以松散耦合的方式进行通信。通过委托,一个对象可以在不直接引用另一个对象的情况下,通知其执行特定的操作。这有助于降低对象之间的依赖性和耦合度,从而提高代码的灵活性和可维护性。

(2)事件驱动编程

委托是实现事件驱动编程的关键机制之一。在事件驱动编程中,对象的行为是基于事件的发生来触发的。委托允许对象在事件发生时通知其他对象,并允许这些对象对事件做出响应。这种机制使得代码更加模块化,并易于扩展和维护。

(3)泛型且类型安全

委托提供了一种泛型但类型安全的方式,在C++对象上调用成员函数。通过委托,你可以动态地绑定到任意对象的成员函数,即使调用程序不知道对象的具体类型也可以进行操作。这增加了代码的灵活性和可重用性,同时保证了类型安全。

(4)异步通信

委托还支持异步通信。在虚幻引擎中,许多操作可能需要花费一些时间才能完成,如加载资源、执行物理模拟等。通过使用委托,你可以在不阻塞主线程的情况下,通知其他对象在异步操作完成后执行特定的操作。这有助于提高应用程序的响应性和性能。

(5)广播和多播

虚幻引擎中的委托还支持广播和多播机制。广播允许一个委托通知所有绑定的对象,而多播则允许一个委托通知多个指定的对象。这种机制使得在多个对象之间传递消息变得更加简单和高效。

(6)蓝图可视化编程支持

在虚幻引擎的蓝图可视化编程环境中,委托也扮演着重要的角色。通过委托,蓝图脚本可以轻松地与C++代码进行交互,从而实现更加复杂和灵活的游戏逻辑。此外,蓝图还支持动态多播委托的声明和使用,这使得在蓝图中处理事件和消息变得更加方便。

(7)复制和安全性

委托对象在复制时是很安全的。你可以通过值或引用来传递委托,但需要注意的是,通过值传递需要在堆上分配内存,这通常不是最佳实践。通过引用传递则更加高效且安全。

但传递引用,在异步的情况下会涉及到生命周期问题,容易崩溃,虚幻的委托大部分时候拷贝是安全的,因为它会存一个执行委托对象的弱引用,如果这对象消亡了,那么这个委托被调用的时候就不会执行。

委托的大致使用流程

  • 声明委托类型
  • 定义委托类型变量
  • 通过委托变量绑定委托函数
  • 执行委托
  • 解绑委托函数(可根据自身情况而实施)

1.单播

先创建一个继承于Actor的类,并在其头文件包含头文件(此处文件命名为LearnSingleDelegateActor)

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "LearnSingleDelegateActor.generated.h"

 并在源文件添加GameplayStatics.h头文件

#include"Kismet/GameplayStatics.h"

(1)声明委托类型 

DECLARE_DELEGATE(FLearnSingleDelegatePrintLocation);
DECLARE_DELEGATE_RetVal_OneParam(FVector,FLearnSingleDelegateGetLocation,FString);
//DECLARE_DELEGATE_RetVal_OneParam(ReturnType, DelegateName, ParamType);
//ReturnType:委托将要返回的值的类型。
//DelegateName:委托的名称,这个名称将用于在代码中引用这个委托类型。
//ParamType:委托将要接受的参数的类型。

如需声明委托,请使用下文所述的宏。请根据与委托相绑定的函数(或多个函数)的函数签名来选择宏。每个宏都为新的委托类型名称、函数返回类型(如果不是 void 函数)及其参数提供了参数。当前,支持以下使用任意组合的委托签名:

  • 返回一个值的函数。
  • 声明为常函数。
  • 最多4个"载荷"变量。
  • 最多8个函数参数。

注意:委托函数支持与UFunctions相同的说明符,但使用 UDELEGATE 宏而不是 UFUNCTION

(2)定义委托类型变量

在ALearnSingleDelegateActor类内定义变量

public:
	FLearnSingleDelegatePrintLocation SingleDelegatePrintLocation;
	FLearnSingleDelegateGetLocation SingleDelegateGetLocation;

(3)通过委托变量绑定委托函数

为方便在ALearnSingleDelegateActor类头文件再创建一个类,此处命名为LearnLocationActor(继承于Actor)

UCLASS()
class ALearnLocationActor : public AActor
{
	GENERATED_BODY()

public:
	ALearnLocationActor();

protected:
	virtual void BeginPlay() override;

	void PrintLocation();
	FVector GetLocation(FString InStr);//此处类型看委托声明处,与其相对应.
};

在此默认函数中创建根组件来便于观察委托操作 ,并对其他函数进行定义

ALearnLocationActor::ALearnLocationActor()
{
	RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("LocationRoot"));
}


void ALearnLocationActor::PrintLocation()
{
	FVector MyLocation = GetActorLocation();
	UE_LOG(LogTemp, Warning, TEXT("[%s]__PrintMyLocation:[%s]"), *FString(__FUNCTION__), *MyLocation.ToString());//用于被绑定时观察步骤实现
}

FVector ALearnLocationActor::GetLocation(FString InStr)
{
	FVector MyLocation = GetActorLocation();
	UE_LOG(LogTemp, Warning, TEXT("[%s]__GetMyLocation:[%s]"), *FString(__FUNCTION__), *MyLocation.ToString());
	return MyLocation;
}

 此处绑定函数

void ALearnLocationActor::BeginPlay()
{
	AActor *ActorPtr = UGameplayStatics::GetActorOfClass(this, ALearnSingleDelegateActor::StaticClass());
	if (ALearnSingleDelegateActor* SingleDelegateActorPtr=Cast<ALearnSingleDelegateActor>(ActorPtr))
	{
        //通过SingleDelegatePrintLocation此委托变量使用BindUObject函数模板绑定委托并调用一次绑定函数
		SingleDelegateActorPtr->SingleDelegatePrintLocation.BindUObject(this,&ALearnLocationActor::PrintLocation);

		SingleDelegateActorPtr->SingleDelegateGetLocation.BindUObject(this, &ALearnLocationActor::GetLocation);
	}
}

 官方模板函数

(4) 执行委托

为了观察实现步骤,我在LearnSingleDelegateActor类声明函数暴露给蓝图

	UFUNCTION(BlueprintCallable, Category = "Learn")
	void CallLocationActorPrint();

	UFUNCTION(BlueprintCallable, Category = "Learn")
	void CallLocationActorGet();

并对其进行定义

void ALearnSingleDelegateActor::CallLocationActorPrint()
{
    //第一种写法
	if (SingleDelegatePrintLocation.IsBound())
	{
		SingleDelegatePrintLocation.Execute();
		//SingleDelegatePrintLocation.Unbind();解绑操作
	}

    //第二种写法(建议用此写法)
	SingleDelegatePrintLocation.ExecuteIfBound();
}

void ALearnSingleDelegateActor::CallLocationActorGet()
{
	FVector MyRecetivedLocation = SingleDelegateGetLocation.Execute(TEXT("My Single Delegate Actor"));
	UE_LOG(LogTemp, Warning, TEXT("[MyRecetivedLocation]__MyLocation:[%s]"), *MyRecetivedLocation.ToString());
}

 注意:对于无返回值的委托,可调用ExecuteIfBound()函数,但需注意输出参数可能未初始化。

(5)观察实现步骤(只做演示)

1、将两个类拖入场景中

2、在关卡蓝图处使用函数(此处是使用键盘1、2分别去激活函数)

3、启动关卡,并在输出日志观察

2.多播

3.动态单播

4.动态多播

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】基础02

Linux编译和调试 VI编辑文件 vi : 进入文件编辑 是命令行模式 i &#xff1a;从光标处进入插入模式 dd : 删除光标所在行 n dd 删除指定行数 Esc &#xff1a; 退出插入模式 &#xff1a; 冒号进入末行模式 :wq : 保存退出 :q &#xff1a; 未修改文件可以退出 :q! …

前端:JavaScript (学习笔记)【1】

目录​​​​​​​ 一&#xff0c;介绍JavaScript 二&#xff0c;JavaScript的特点 1&#xff0c;脚本语言 2&#xff0c;基于对象的语言 3&#xff0c;事件驱动 4&#xff0c;简单性 5&#xff0c;安全性 6&#xff0c;跨平台性 7&#xff0c;JS 和java的区别 &…

安卓手机root+magisk安装证书+抓取https请求

先讲一下有这篇文章的背景吧&#xff0c;在使用安卓手机fiddler抓包时&#xff0c;即使信任了证书&#xff0c;并且手机也安装了证书&#xff0c;但是还是无法捕获https请求的问题&#xff0c;最开始不知道原因&#xff0c;后来慢慢了解到现在有的app为了防止抓包&#xff0c;把…

数字化那点事:一文读懂物联网

一、物联网是什么&#xff1f; 物联网&#xff08;Internet of Things&#xff0c;简称IoT&#xff09;是指通过网络将各种物理设备连接起来&#xff0c;使它们可以互相通信并进行数据交换的技术系统。通过在物理对象中嵌入传感器、处理器、通信模块等硬件&#xff0c;IoT将“…

Tomcat和Nginx原理说明

Tomcat Tomcat 是一个开源的 Java 应用服务器&#xff0c;它由多个关键组件组成。这些组件共同协作&#xff0c;实现了 Servlet 容器的功能。以下是 Tomcat 的核心组件说明及其逻辑架构的示意图。 1. Tomcat 核心组件说明 (1) Server 描述&#xff1a;Tomcat 的顶级组件&…

【大模型】LLaMA: Open and Efficient Foundation Language Models

链接&#xff1a;https://arxiv.org/pdf/2302.13971 论文&#xff1a;LLaMA: Open and Efficient Foundation Language Models Introduction 规模和效果 7B to 65B&#xff0c;LLaMA-13B 超过 GPT-3 (175B)Motivation 如何最好地缩放特定训练计算预算的数据集和模型大小&…

一文解决Latex中的eps报错eps-converted-to.pdf not found: using draft setting.

在使用Vscode配的PDFLatex编译IEEE TII的Latex模板时&#xff0c;出现eps文件不能转换为pdf错误&#xff0c;看了几十篇方法都没用&#xff0c;自己研究了半天终于可以正常运行了。主要原因还是Settings.JSON中的PDFLatex模块缺少&#xff1a;"--shell-escape", 命令…

【流量分析】常见webshell流量分析

免责声明&#xff1a;本文仅作分享&#xff01; 对于常见的webshell工具&#xff0c;就要知攻善防&#xff1b;后门脚本的执行导致webshell的连接&#xff0c;对于默认的脚本要了解&#xff0c;才能更清晰&#xff0c;更方便应对。 &#xff08;这里仅针对部分后门代码进行流量…

Java前端基础——CSS

一、CSS介绍 1.1 什么是CSS CSS(Cascading Style Sheet)&#xff0c;层叠样式表,用于控制页面的样式. CSS 能够对网页中元素位置的排版进行像素级精确控制, 实现美化页面的效果. 能够做到页面的样式和结构分离. 1.2 基本语法规范 选择器 {⼀条/N条声明} • 选择器决定针…

游戏引擎学习第17天

视频参考:https://www.bilibili.com/video/BV1LPUpYJEXE/ 回顾上一天的内容 1. 整体目标&#xff1a; 处理键盘输入&#xff1a;将键盘输入的处理逻辑从平台特定的代码中分离出来&#xff0c;放入更独立的函数中以便管理。优化消息循环&#xff1a;确保消息循环能够有效处理 …

知识中台:赋能 3C 数码企业服务升级

在数字化浪潮汹涌澎湃的当下&#xff0c;3C 数码产品行业竞争已呈白热化态势。企业如何在这片充满挑战与机遇的领域中&#xff0c;打造卓越服务&#xff0c;构筑核心竞争力&#xff1f;知识中台的建设与运用&#xff0c;正逐渐成为破题关键。 一、产品研发加速引擎 在 3C 数码…

_FYAW智能显示控制仪表的简单使用_串口通信

一、简介 该仪表可以实时显示位移传感器的测量值&#xff0c;并可设定阈值等。先谈谈简单的使用方法&#xff0c;通过说明书&#xff0c;我们可以知道长按SET键可以进入参数选择状态&#xff0c;按“↑”“↓”可以选择该组参数的上一个或者下一个参数。 从参数一览中可以看到有…

Pytest 学习 @allure.severity 标记用例级别的使用

一、前言 使用allure.serverity注解&#xff0c;可以在allure报告中清晰的看到不同级别用例情况 使用等级介绍 allure提供的枚举类 二、等级介绍 二、等级介绍 blocker&#xff1a;阻塞缺陷&#xff08;功能未实现&#xff0c;无法下一步&#xff09; critical&#xff1a;…

Linux编辑器 - vim

目录 一、vim 的基本概念 1. 正常/普通/命令模式(Normal mode) 2. 插入模式(Insert mode) 3. 末行模式(last line mode) 二、vim 的基本操作 三、vim 正常模式命令集 1. 插入模式 2. 移动光标 3. 删除文字 4. 复制 5. 替换 6. 撤销上一次操作 7. 更改 8. 调至指定…

windows下编译ffmpeg4.4版本

最近在做一个利用ffmpeg库播放rtsp流的一个项目&#xff0c;需要自己编译ffmpeg源码&#xff1b;记录一下编译源码的过程&#xff0c;仅供参考&#xff1b; 目标&#xff1a; 开发环境&#xff1a;windows10系统&#xff1b; ffmpeg:ffmpeg4.4版本&#xff0c;https://downlo…

vulfocus在线靶场:骑士cms_cve_2020_35339:latest 速通手册

目录 一、启动环境&#xff0c;访问页面&#xff0c;ip:端口号/index.php?madmin,进入后台管理页面&#xff0c;账号密码都是adminadmin 二、进入之后&#xff0c;根据图片所示&#xff0c;地址后追加一下代码&#xff0c;保存修改 ​三、新开标签页访问&#xff1a;①ip:端…

鸿蒙开发:ForEach中为什么键值生成函数很重要

前言 在列表组件使用的时候&#xff0c;如List、Grid、WaterFlow等&#xff0c;循环渲染时都会使用到ForEach或者LazyForEach&#xff0c;当然了&#xff0c;也有单独使用的场景&#xff0c;如下&#xff0c;一个很简单的列表组件使用&#xff0c;这种使用方式&#xff0c;在官…

力扣 LeetCode 257. 二叉树的所有路径(Day8:二叉树)

解题思路&#xff1a; 第一次提到回溯 前序遍历 中左右 中是处理过程 左右是递归过程 注意递归三部曲的第二部&#xff0c;确定终止条件&#xff0c;这里就是遍历完叶子节点就停止&#xff0c;而不是遍历到空节点 class Solution {List<String> res new ArrayLis…

el-table实现最后一行合计功能并合并指定单元格

效果图如下&#xff1a; 表格代码如下&#xff1a; <el-table width"100%"ref"tableRef" style"margin-bottom: 15px;":data"jlData"class"tableHeader6"header-row-class-name"headerStyleTr6":row-class-n…

Java基础知识(六)

文章目录 StringString、StringBuffer、StringBuilder 的区别&#xff1f;String 为什么是不可变的?字符串拼接用“” 还是 StringBuilder?String#equals() 和 Object#equals() 有何区别&#xff1f;字符串常量池的作用了解吗&#xff1f;String s1 new String("abc&qu…