UE_C++ —— Delegates

Unreal引擎C++与蓝图通信模式与性能优化 在游戏开发中,引擎底层与逻辑层的通信架构设计直接影响项目质量和开发效率。Unreal引擎通过C++与蓝图的双向通信机制,实现了高性能底层与灵活逻辑的完美结合。核心原理是利用UFUNCTION宏系统和元数据控制,建立类型安全的跨语言调用通道。技术价值体现在既保持C++的性能优势,又发挥蓝图的快速迭代特性,特别适合角色控制、UI系统和游戏逻辑等场景。本文以BlueprintCallable和动态多播委托为例,结合性能测试数据,深入分析通信开销优化方案,并分享内存对齐、异步操作等实战经验,帮助开发者构建高效的Un 阅读详情

目录

一,Single

Declaring Delegates

Binding Delegates

Executing Delegates

Example Usage

二,Multicast

三,Dynamic


委托 可理解为是一种类型安全的函数指针容器,存储目标对象及其成员函数的地址;

  • 委托可动态绑定到任意对象的成员函数,之后在该对象上调用函数,即使调用者不知对象类型;
  • 委托可很安全的复制;
  • 也可值传递委托,但这样操作需要在堆上分配内存,因此通常并不推荐;请尽量通过引用传递委托;

UE 共支持三种类型的委托:

  • Single

  • Multicast

  • Dynamic (UObject, serializable)

注:

  • Event Dispatcher 为蓝图原生的委托,本质上是动态多播委托;
  • 蓝图中的内置事件
    • 一种是已绑定到动态多播委托上的回调函数(UFUNCTION),会在触发时调用Broadcasst(),如 OnComponentHit/OnComponentBeginOverlap、InputAction/EnhancedInputAction ;
    • 一种是 C++ 虚函数,如 BeginPlay、Tick、EndPlay、Destroyed ;如BeginPlay事件对应的是ReceiveBeginPlay();
  • 蓝图中的自定义事件只是普通函数(UFUNCTION);

一,Single

Declaring Delegates

        使用宏声明委托,根据绑定的函数签名来选择宏,每个宏都包含新委托类型的名称,返回类型(如不是void)及其参数;委托签名声明可存在于全局范围内、命名空间内、甚至类声明内,可能不存在于函数体内;当前,支持以下委托签名:

  • 返回一个值的函数;
  • 声明为 const 函数;
  • 最多4个"payload"变量;
  • 最多8个函数参数;
// 无返回值声明
void Function() 
    ---> DECLARE_DELEGATE(DelegateName)
void Function(Param1)
    ---> DECLARE_DELEGATE_OneParam(DelegateName, Param1Type)
void Function(Param1, Param2)
    ---> DECLARE_DELEGATE_TwoParams(DelegateName, Param1Type, Param2Type)
void Function(Param1, Param2, ...)
    ---> DECLARE_DELEGATE_<Num>Params(DelegateName, Param1Type, Param2Type, ...)
// 有返回值声明
<RetValType> Function()
    ---> DECLARE_DELEGATE_RetVal(RetValType, DelegateName)
<RetValType> Function(Param1)
    ---> DECLARE_DELEGATE_RetVal_OneParam(RetValType, DelegateName, Param1Type)
<RetValType> Function(Param1, Param2)
    ---> DECLARE_DELEGATE_RetVal_TwoParams(RetValType, DelegateName, Param1Type, Param2Type)
<RetValType> Function(Param1, Param2, ...)
    ---> DECLARE_DELEGATE_RetVal_<Num>Params(RetValType, DelegateName, Param1Type, Param2Type, ...)
Binding Delegates

        将委托绑定到UObject或共享指针类的成员, 委托系统可保留对该对象的弱引用,因此该对象在代理之外被销毁时,可通过调用 IsBound() 或 ExecuteIfBound() 函数进行判断;

委托绑定:“对象实例 + 成员函数指针”,函数应为公有的;

注意各类受支持对象的特殊绑定语法;

FunctionDescription
Bind绑定到现有委托对象;
BindStatic绑定原始C++指针全局函数委托;
BindRaw绑定原始C++指针委托;
由于原始指针不使用任何类型的引用,因此在删除目标对象后调用 Execute 或 ExecuteIfBound 会不安全;
BindLambda绑定一个functor,通常用于拉姆达函数;
BindSP绑定基于指针的共享成员函数委托;
共享指针委托会保留对对象的弱引用;
可使用 ExecuteIfBound() 进行调用;
BindUObject绑定 UObject 的成员函数委托;
UObject 委托会保留对对象 UObject 的弱引用;
可使用 ExecuteIfBound() 进行调用;
UnBind取消绑定此委托;

注,..\Engine\Source\Runtime\Core\Public\Delegates\DelegateSignatureImpl.inl 可了解这些函数的变体、参数和实现;

Payload Data

        在绑定到委托时,可传递有效负载数据(可以是任意变量);在绑定函数被调用时,会直接传递给任何绑定函数;所有委托类型(除“dynamic”外)都自动支持有效负载变量;

// 此例将两个自定义变量(一个布尔,一个int32)传递到委托;
// 调用该委托时,参数将被传到绑定函数;额外的变量参数必须始终在委托类型参数之后被接受;
MyDelegate.BindRaw( &MyFunction, true, 20 );
Executing Delegates

        通过调用委托的 Execute() 函数执行绑定到委托的函数;执行前须检查委托是否已绑定,以使代码更安全;因为有时委托可能含有未初始化且被后续访问的返回值和输出参数; 执行未绑定的委托在某些情况下确实可能导致内存混乱;

        可调用 IsBound() 检查是否可安全执行委托; 同时,对于无返回值的委托,可调用 ExecuteIfBound(),但需注意输出参数可能未初始化;

Execute        // 执行一个委托而不检查其绑定情况;
ExecuteIfBound // 检查委托是否已绑定,如是,则调用Execute;
IsBound        // 检查委托是否已绑定,通常在包含Execute调用的代码之前进行;
Example Usage
// 假定类拥有可在任何地方随意调用的方法
class FLogWriter {
public:
	void WriteToLog(FString);
};
// 首先需使用宏声明委托;要调用 WriteToLog 函数,需创建该函数签名的委托类型;
// 创建名为 FStringDelegate 的委托类型,使用单个参数 FString ;
DECLARE_DELEGATE_OneParam(FStringDelegate, FString); 

class FMyClass {
    // 在类中创建 FStringDelegate 对象
	FStringDelegate WriteToLogDelegate;
};
// 委托时只需创建委托类的实例,将拥有该方法的类作为模板参数传递;
// 传递对象的实例和实际函数地址;
TSharedRef<FLogWriter> LogWriter(new FLogWriter());
WriteToLogDelegate.BindSP(LogWriter, &FLogWriter::WriteToLog);
// FMyClass 即可调用 WriteToLog 方法,甚至无需了解 FLogWriter 类的任何信息!
WriteToLogDelegate.Execute(TEXT("Delegates are great!"));
// 多数情况下,建议使用以下操作
WriteToLogDelegate.ExecuteIfBound(TEXT("Only executes if a function was bound!"));

二,Multicast

        多播委托具有与单播委托大多数相同的功能;仅对对象具有弱引用,可与结构体一起使用,可轻松地复制等;与常规委托一样,多播委托可以被加载/保存,并可以远程触发;但多播委托函数不能使用返回值;

// 声明多播委托,与声明标准委托方式上相同
DECLARE_MULTICAST_DELEGATE[_RetVal, ...]\( DelegateName \)
DECLARE_DYNAMIC_MULTICAST_DELEGATE[_RetVal, ...]\( DelegateName \)
FunctionDescription
Add()将函数添加到该多播委托的调用列表中
AddStatic()添加原始C++指针全局函数委托;
AddRaw()

添加原始C++指针委托;

原始指针不使用任何类型的引用,因此如果从委托下面删除了对象,则调用此函数可能不安全。调用Execute()时请小心!

AddLambda()添加一个 functor,通常用于那些不会捕获指针的lambda函数;
AddSPLambda()添加一个 functor,只有在对目标共享指针的弱引用有效的情况下才会被调用;
AddWeakLambda()添加一个 functor,只有在对UObject的弱引用有效的情况下才会被调用;
AddSP()

添加基于共享指针的(快速、非线程安全)成员函数委托;

共享指针委托保留对对象的弱引用;

AddUObject()

添加基于UObject的成员函数委托;

UObject委托保留对对象的弱引用;

Remove()

从该多播委托的调用列表中删除函数(性能为O(N));

请注意,委托的顺序可能不会被保留!

RemoveAll()

从该多播委托的调用列表中删除绑定的所有函数;

请注意,委托的顺序可能不会被保留!

删除绑定到所提供指针的所有已注册委托,未绑定到对象指针的原始委托不会被该函数所删除!

注,..\Engine\Source\Runtime\Core\Public\Delegates\DelegateSignatureImpl.inl 可了解这些函数的变体、参数和实现;

// 将该委托广播给所有绑定的对象;
// 调用该函数总是安全的,即使没有任何绑定时也是如此;
// 唯一需要注意的是,如使用委托来初始化输出变量,通常会带来非常不利的后果;
// 调用时绑定函数的执行顺序尚未定义,执行顺序可能与函数的添加顺序不相同;
Broadcast()

三,Dynamic

        动态委托可序列化且支持反射的委托,通过反射来查找函数名称以实现绑定,但其执行速度比常规委托慢;其绑定的函数需使用UFUNCTUION()标记;宏声明的类型名称必须以 F 开头,最多支持 9 个参数(在多使用结构体封装);

// 声明动态委托,与声明标准委托方式上相同
// 动态单播委托
DECLARE_DYNAMIC_DELEGATE[_RetVal, ...]\( DelegateName \)
// 动态多播委托,最常用,支持蓝图;
DECLARE_DYNAMIC_MULTICAST_DELEGATE[_RetVal, ...]\( DelegateName \)
// 委托函数支持与UFunctions相同的说明符,但是使用 UDELEGATE 宏而不是 UFUNCTION;
// 参数禁止引用,宏内必须同时写参数类型和参数名;
UDELEGATE(BlueprintAuthorityOnly)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FInstigatedAnyDamageSignature, float, Damage, const UDamageType*, DamageType, AActor*, DamagedActor, AActor*, DamageCauser);
FunctionDescription
BindDynamic( UserObject, FuncName )用于在动态委托上调用BindDynamic()的辅助宏,自动生成函数命名字符串;
AddDynamic( UserObject, FuncName )用于在动态多播委托上调用AddDynamic()的辅助宏,自动生成函数命名字符串;
RemoveDynamic( UserObject, FuncName )

用于在动态多播委托上调用RemoveDynamic()的辅助宏,自动生成函数命名字符串;

// 执行动态委托
Execute        // 执行一个委托而不检查其绑定情况;
ExecuteIfBound // 检查委托是否已绑定,如是,则调用Execute;
IsBound        // 检查委托是否已绑定,通常在包含Execute调用的代码之前进行;
// Button.h 源代码头文件中声明的动态多播
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnButtonClickedEvent);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnButtonPressedEvent);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnButtonReleasedEvent);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnButtonHoverEvent);
// UButton 成员变量
UPROPERTY(BlueprintAssignable, Category="Button|Event") // BlueprintAssignable:允许在蓝图中绑定事件
FOnButtonClickedEvent OnClicked;
// .h 文件设置属性
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (BindWidget))
TObjectPtr<UButton> Start;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (BindWidget))
TObjectPtr<UButton> Quit;

// .cpp 文件
bool UMyUserWidget::Initialize() {
	if(!Super::Initialize())
		return false;
	Start->OnClicked.AddDynamic(this, &UMyUserWidget::StartFunc);
	Quit->OnClicked.AddDynamic(this, &UMyUserWidget::QuitFunc);
	return true;
}

四,稀疏动态多播

稀疏动态多播与标准的动态多播功能基本一致,但核心区别在于它是一种内存优化方案;

  • 标准动态多播,包含该委托的对象,无论是否有人监听,都会为其分配存储调用列表的内存,开销较大;
    • 适用于高频触发、或绝大多数实例都会被监听的事件;
  • 稀疏动态多播,在没有人绑定时,只占用1个字节的内存(仅存储一个 bIsBound 标志),只有当第一次有人绑定时,才会在全局存储中创建真正的调用列表;
    • 适用于低频触发、绝大多数实例不会被监听的事件;

蓝图事件节点对应的C++委托类型对应头文件说明
On Component HitFComponentHitSignatureUPrimitiveComponent碰撞命中
On Component Begin OverlapFComponentBeginOverlapSignature开始重叠
On Component End OverlapFComponentEndOverlapSignature结束重叠
On Component WakeFComponentWakeSignature物理模拟唤醒
On Component SleepFComponentSleepSignature物理模拟休眠
On Component Physics State ChangedFComponentPhysicsStateChanged物理状态变化
On Begin Cursor OverFOnBeginCursorOver鼠标悬停开始
On End Cursor OverFOnEndCursorOver鼠标悬停结束
On ClickedFOnClicked鼠标点击
On ReleasedFOnReleased鼠标释放
On Input Touch Begin/End/Enter/LeaveFOnInputTouchBegin触摸输入事件
Physics Volume ChangedFPhysicsVolumeChangedSceneComponent.h物理体积改变
On Component ActivatedFActorComponentActivatedSignatureActorComponent.h组件激活
On Component DeactivatedFActorComponentDeactivateSignature组件失活
// PrimitiveComponent.h 源代码头文件内声明的稀疏动态多播
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams( FComponentHitSignature, UPrimitiveComponent, OnComponentHit, UPrimitiveComponent*, HitComponent, AActor*, OtherActor, UPrimitiveComponent*, OtherComp, FVector, NormalImpulse, const FHitResult&, Hit );

DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SixParams( FComponentBeginOverlapSignature, UPrimitiveComponent, OnComponentBeginOverlap, UPrimitiveComponent*, OverlappedComponent, AActor*, OtherActor, UPrimitiveComponent*, OtherComp, int32, OtherBodyIndex, bool, bFromSweep, const FHitResult &, SweepResult);
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams( FComponentEndOverlapSignature, UPrimitiveComponent, OnComponentEndOverlap, UPrimitiveComponent*, OverlappedComponent, AActor*, OtherActor, UPrimitiveComponent*, OtherComp, int32, OtherBodyIndex);

DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams(FComponentWakeSignature, UPrimitiveComponent, OnComponentWake, UPrimitiveComponent*, WakingComponent, FName, BoneName);
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams(FComponentSleepSignature, UPrimitiveComponent, OnComponentSleep, UPrimitiveComponent*, SleepingComponent, FName, BoneName);
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam(FComponentCollisionSettingsChangedSignature, UPrimitiveComponent, OnComponentCollisionSettingsChangedEvent, UPrimitiveComponent*, ChangedComponent);
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams(FComponentPhysicsStateChanged, UPrimitiveComponent, OnComponentPhysicsStateChanged, UPrimitiveComponent*, ChangedComponent, EComponentPhysicsStateChange, StateChange);

DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam( FComponentBeginCursorOverSignature, UPrimitiveComponent, OnBeginCursorOver, UPrimitiveComponent*, TouchedComponent );
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam( FComponentEndCursorOverSignature, UPrimitiveComponent, OnEndCursorOver, UPrimitiveComponent*, TouchedComponent );

DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams( FComponentOnClickedSignature, UPrimitiveComponent, OnClicked, UPrimitiveComponent*, TouchedComponent , FKey, ButtonPressed);
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams( FComponentOnReleasedSignature, UPrimitiveComponent, OnReleased, UPrimitiveComponent*, TouchedComponent, FKey, ButtonReleased);

DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams( FComponentOnInputTouchBeginSignature, UPrimitiveComponent, OnInputTouchBegin, ETouchIndex::Type, FingerIndex, UPrimitiveComponent*, TouchedComponent );
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams( FComponentOnInputTouchEndSignature, UPrimitiveComponent, OnInputTouchEnd, ETouchIndex::Type, FingerIndex, UPrimitiveComponent*, TouchedComponent );
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams( FComponentBeginTouchOverSignature, UPrimitiveComponent, OnInputTouchEnter, ETouchIndex::Type, FingerIndex, UPrimitiveComponent*, TouchedComponent );
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams( FComponentEndTouchOverSignature, UPrimitiveComponent, OnInputTouchLeave, ETouchIndex::Type, FingerIndex, UPrimitiveComponent*, TouchedComponent );
// UPrimitiveComponent 成员变量,BlueprintAssignable允许蓝图内Bind Event节点绑定
UPROPERTY(BlueprintAssignable, Category="Collision")
FComponentBeginOverlapSignature OnComponentBeginOverlap;
// 调用 AddDynamic 绑定组件的重叠事件
// 触发重叠事件还需:双方都开启Generate Overlap Events,碰撞预设为Overlap,静态网格体要有碰撞体
// AddDynamic()辅助宏,用于动态多播委托(实际调用__Internal_AddDynamic)
myCube->OnComponentBeginOverlap.AddDynamic(this, &AMyActor::OnOverlapBegin);

// 回调函数必须标记UFUNCTION(),且参数完全一致
UFUNCTION()
void OnOverlapBegin(UPrimitiveComponent* OverlappedComponent,
	AActor* OtherActor,
	UPrimitiveComponent* OtherComp,
	int32 OtherBodyIndex,
	bool bFromSweep,
	const FHitResult& SweepResult);

注意:BeginPlay 的执行顺序(先是所有Actor C++的BeginPlay -> 所有Actor 蓝图的BeginPlay -> 关卡蓝图的BeginPlay);

虚幻引擎C++物理交互:从零构建物体抓取与移动系统 在游戏开发与虚拟现实应用中,物理交互是实现沉浸式体验的核心技术之一。其基本原理是通过碰撞检测、物理模拟与输入响应,让虚拟物体能够被用户操作并产生符合物理规律的行为。这项技术的核心价值在于提升交互的真实感与自由度,广泛应用于VR抓取、物理解谜、建筑摆放等场景。在虚幻引擎中,开发者常通过蓝图快速原型,但转向C++实现时,需要处理物理手柄组件、射线检测、交互接口等底层机制,以实现更高效、可维护的物理交互系统。本文聚焦于UEC++实现,提供从组件创建到平滑移动的完整解决方案,帮助开发者掌握物理交互的底层实现,并优化 阅读详情

相关推荐

UnrealCLR实战:C#与虚幻引擎5深度集成与调试指南

在游戏开发领域,托管代码与原生引擎的集成是提升开发效率的关键技术。其核心原理是通过桥接层实现运行时环境的互操作,允许开发者使用熟悉的语言和工具链调用底层引擎功能。这一技术价值在于能够结合托管语言的高生产力和原生引擎的高性能,特别适用于需要快速迭代逻辑、复用现有代码库或整合丰富第三方库的项目场景。例如,利用C#的LINQ进行数据查询、依赖注入管理复杂对象生命周期,可以显著提升游戏系统代码的可维护性。本文聚焦于UnrealCLR这一具体解决方案,针对环境配置、双向通信和混合调试三大核心挑战,提供了从工具链精确匹

363

函数指针

函数指针是指向函数的指针变量。 因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上是一致的。函...

weixin_34277853的博客 231

虚幻引擎AI编程助手:UEHttpGPT插件架构与集成实践

在软件工程领域,AI代码生成与智能辅助正成为提升开发效率的关键技术。其核心原理是通过大语言模型理解自然语言意图,并生成或补全结构化代码。这项技术的价值在于能显著降低学习成本、加速原型验证,并辅助处理重复性编码任务。在游戏开发,特别是虚幻引擎这类复杂框架中,开发者常面临专属API体系庞大、蓝图与C++混合编程等挑战,通用AI工具往往难以精准适配。UEHttpGPT插件正是针对这一场景的解决方案,它通过HTTP通信层将ChatGPT等模型能力深度集成到编辑器内部,实现了上下文感知的代码生成与问答。该插件采用分层

weixin_34081595的博客 1012

在 C/C++ 中实现委托(delegate)

  相信使用过C#语言的人们,对于委托应该是记忆深刻,委托具有很多不错的特性,但最令人感到兴奋的是它可以简化很多复杂的开发同时具有低耦合与对象闭包的特性。    委托在C/C++中可以解决最直观的就有问题,一个是相同代码签名的成员函数与全局函数可以被一个委托调用的问题,在C/C++语言中我们在不借助委托的前提下,代码很难在不增加耦合与依赖的情况调用它们(无论这个依赖是隐式的还是显式的都会存在这个...

liulilittle的博客 1万+

C++笔记之Delegate和委托构造(Delegating constructor)

— 2023-12-10。

小勇博客 1750

C++中实现委托(delegate)

网上有很多关于C++ delegate机制的文章,但都讲的是函数指针的内容,上周就C++中实现C#的delegate机制的问题研究了好几天,查看了很多相关资料,才解决了问题,现将我写的C++ delegate测试程序贴出来,希望能帮到有需要的人。

《UE5_C++多人TPS完整教程》学习笔记20 ——《P21 更多的子系统委托(More Subsystem Delegates)》

本节课将创建更多的子系统委托,包括搜索、加入、销毁和开始会话委托,然后创建与它们分别绑定的回调函数。

m0_55220082的博客 2981

C++实现delegate

用C++做项目的时候,尤其是写客户端的时候经常会有事件回调的设计,一般的方式是使用虚函数表,用一个虚基类包含一系列的回调函数。但这种方式和C++11的lamda不兼容,为了更方便的实现事件回调机制,使用delegate是很不错的一种方式。

《UE5_C++多人TPS完整教程》学习笔记15 ——《P16 会话接口委托(Session Interface Delegates)》

本节课我们将向新创建的子系统添加会话接口函数、委托及与其绑定的回调函数、委托句柄(保存委托,以便在委托完成时能将其移出委托列表)。

m0_55220082的博客 1572

Windows下Python调用D435i相机避坑指南:从SDK版本选择到RealSense Viewer报错解决

本文详细介绍了在Windows环境下使用Python调用Intel D435i相机的完整避坑指南。重点解决了SDK版本选择问题,推荐使用稳定的Intel RealSense SDK 2.54.2版本,并提供了从环境配置、常见报错解决到实际应用案例的全流程实践指导,帮助开发者高效完成相机部署与开发。

palm99的专栏 923

芯片详解——AD7606

AD7606详解

weixin_45661757的博客 5021

深入理解UE5委托(Delegates):从创建会话的案例看C++异步通信如何简化多人游戏逻辑

本文深入解析了UE5委托系统在多人游戏开发中的关键作用,特别是通过创建会话的案例展示了C++异步通信如何简化复杂逻辑。文章详细介绍了委托系统的设计哲学、会话创建流程中的应用、与其他异步机制的对比,以及高级委托模式和最佳实践,帮助开发者构建高效的多人游戏通信框架。

weixin_33730836的博客 503

告别复杂配置!用GuidosToolbox 3.0做MSPA景观格局分析,从安装到出图全记录

本文详细介绍了如何使用GuidosToolbox 3.0进行MSPA景观格局分析,从安装配置到出图全流程。涵盖环境准备、数据预处理、参数设置、结果解读及可视化技巧,帮助用户快速掌握这一生态安全评估工具。特别针对安装教程中的常见问题提供解决方案,提升分析效率。

weixin_29248313的博客 489

[UE4]中的函数回调实现

UE4中的函数回调(CallBack) C++中应该有许多种方式的回调,UE C++(UnrealEngine中的C++)则是使用的DELEGATE和EVENT来实现。 关于UE C++的代理,存在着以下的几种方式: 静态的Single-cast Delegates Dynamic Single-cast Delegates 静态的Multi-cast Delegates Dynami...

qq173681019的博客 8207

保姆级教程:用STM32H743+TJA1042T玩转FDCAN,CubeMX配置1M/5M双速率通信(附完整代码)

本文提供STM32H743与TJA1042T实现FDCAN双速率通信的保姆级教程,详细讲解CubeMX配置1M/5M双速率通信的全过程,包括硬件连接、时钟树配置、过滤器设置及中断管理,并附完整代码示例,助力开发者快速掌握FDCAN高速通信技术。

weixin_30698297的博客 473

Android以太网开关流程分析

Android以太网开关流程分析 一、引言   在Android 以太网服务启动流程中我们启动了EthernetService(ES),NetworkManagementService(NMS)等服务,其中ES作为Binder的服务端,向客户端EthernetManger提供了调用接口的引用。因此,应用可以通过EthernetManger来访问以太网的相关接口。本篇文章将从APP调用以太网的使能和关闭的接口流程作为切入点来分析,以太网框架中,上层app是如何将指令传递到底层。图1-1所示为以太网使能和关闭

franc521的博客 6113

UE_C++ —— UFunctions

UFunctions 函数;

NapoleonCoder的博客 1038

SPI扩展CAN方案:从寄存器配置到多路通信实战

本文详细介绍了SPI扩展CAN方案的实现方法,从寄存器配置到多路通信实战。通过使用MCP2517FD芯片和SPI接口,可低成本扩展多路CAN通道,适用于工业控制领域。文章涵盖硬件设计、寄存器配置、中断优化及性能调优等核心内容,帮助开发者高效解决设备节点过多的问题。

weixin_42657024的博客 362

[UE4]代理事件(C++)

用宏定义类似格式: DECLARE_DELEGATE //普通代理 DECLARE_DYNAMIC_DELEGATE_TwoParams //动态代理 DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams //动态多广播代理 //多出的两个关键字的作用 In the case of multicast delegates, a...

weixin_30457881的博客 231

46、大数据助力SDN优化流量管理与控制器

本文探讨了大数据在软件定义网络(SDN)中的应用,重点分析了如何利用大数据技术优化SDN控制器的可扩展性和弹性。通过介绍SDN控制器的核心功能及其面临的挑战,提出了集中式、分布式、混合式和分层式控制器放置策略,并结合大数据分析系统架构与技术,详细阐述了在控制器放置优化、流聚合和备份路径识别等场景中的实际应用。文章还给出了大数据分析在SDN控制器优化中的操作流程与优势,展望了未来结合人工智能与物联网的发展方向,强调了数据安全与算法效率的重要性。

xx56789的博客 86

Spring Security 珍藏版快速入门

文章目录一、前期配置二、Spring Security 测试三、案例:自定义页面(XML配置用户信息)三、案例:自定义页面(数据库存储用户信息) 一、前期配置 (1)pom.xml <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${s

南淮北安的博客 633

UE5.6的AbilitySystemComponent.h文件注释

这是一个非常庞大的头文件,包含了 Unreal Engine 中 Ability System 的核心组件 的定义。 关键部分的中文注释,包括:这个组件是 Unreal Engine 游戏玩法能力系统的核心,负责管理游戏中的能力、效果、属性和标签系统。

chenchaoNH的博客 417

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

揭秘Unreal Engine插件架构:如何用C++实现高效扩展与热重载

掌握C++ Unreal Engine插件开发核心技巧,实现高效功能扩展与热重载。适用于游戏模块化开发与工具链集成,通过动态库加载与反射机制提升迭代效率。详解插件结构、编译配置与实时调试方案,开发效率大幅提升,值得收藏。

StepLens的博客 1008

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

虚幻引擎C++开发:从标准语法到引擎核心机制的思维转换与实践指南

C++作为高性能游戏开发的核心语言,其内存管理、对象生命周期和模板机制是构建复杂系统的基础。在游戏引擎领域,这些基础原理被扩展为与编辑器深度集成、支持数据驱动和跨平台运行的特定框架。虚幻引擎(Unreal Engine)的C++开发便是这一技术价值的典型体现,它通过宏系统(如UCLASS、UPROPERTY)、反射机制和独特的对象模型(UObject),重塑了代码的组织与交互方式,极大地提升了开发效率和协作能力。这种“引擎化”的C++广泛应用于3A游戏、实时可视化及虚拟制片等高性能图形应用场景。本文聚焦于*

weixin_34293911的博客 494

虚幻引擎5.8集成MySQL/MariaDB数据库:从原理到实战应用

在虚幻引擎(UE)项目中,当我们需要处理玩家数据、排行榜、配置信息或任何需要持久化存储的游戏状态时,本地文件或简单的数据表往往显得力不从心。这时,一个成熟的关系型数据库就显得至关重要。然而,直接在 UE 的 C++ 或蓝图中连接和操作 MySQL/MariaDB 并非易事,需要处理网络连接、SQL 协议、线程安全等一系列复杂问题。 “UE-MySQL 与 MariaDB 集成 v4.1(5.8)” 插件正是为了解决这一痛点而生。它封装了底层的数据库连接和操作逻辑,为开发者提供了一套简洁、直观的蓝图节点和 C

congtaixiao7151的博客 432

解决VRM4U动态材质丢失:虚幻引擎材质缓存机制与持久化方案

在实时渲染和游戏开发中,材质系统是决定视觉表现的核心组件。其原理基于着色器编译、参数传递和资源引用,通过GPU管线实现复杂的光照与表面效果。材质系统的技术价值在于平衡视觉质量与运行时性能,同时提供灵活的艺术创作空间。在动态内容加载、跨平台资源管理等应用场景下,材质资产的生命周期管理与缓存一致性成为常见挑战。例如,当使用VRM4U插件在虚幻引擎中动态加载VRM模型时,常遇到材质参数重置或引用丢失问题,这本质上是引擎的静态资产管线与动态资源创建机制之间的冲突。通过理解材质实例常量(MIC)与动态材质实例(MID

weixin_30908103的博客 347
上一篇: UE_C++ —— Logging in Unreal
下一篇: Blueprint —— Connecting Nodes
挨代码
博客等级 码龄5年 1696粉丝 384原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值