UE委托的使用

参考文章:

Delegate(委托)

UE4 C++进阶进行中

UE4代理上

一文理解透UE委托Delegate

UE官方文档

委托简介

委托本质上是一个函数指针的封装,它可以绑定一个函数,之后在某个时刻调用这个函数。

主要作用是将实时监测的逻辑转换为触发式逻辑,同时降低代码之间的耦合性

常用的委托有单播、多播、动态多播和事件等;

上述委托的概念不在赘述,详细请参考UE官方文档一文理解透UE委托Delegate以及上面提及的视频连接

委托的使用

由于每种委托的使用方法几乎一样,在此只使用单播作为介绍委托的使用。

委托使用的原理

下图是委托的整个事件类型

deepseek_mermaid_20250719_206cfb

下图是使用委托的三个基本类

image-20250719184658679

从上图可以看到,使用委托和不使用委托的区别,使用委托可以降低事件触发类和被调用类之间的耦合,将这两个类的操作放在委托制造类里面进行操作,这对于大型项目十分重要。

这里做个比喻就是:你点了一家饭店的吃饭,你要吃的饭汇报给饭店,饭店指定厨师做饭并将饭端给你。这里的你就是事件触发类,饭店就是委托制造类,厨师就是被调用类。

代码实现

这里的代码修改了 UEC++实现人物按照A星路线移动 里面的算法,有需要可以去参考

事件触发类

AStar_test2Character.h

// 获取委托
UMyDelegateMaker* Maker;

AStar_test2Character.cpp

void AAStar_test2Character::SpineSet()
{
	UWorld* World = GetWorld();
	if (Maker == nullptr)
	{
		Maker = NewObject<UMyDelegateMaker>();
	}
    // 绑定并执行委托
	Maker->BindSpineSet(World).Execute();
	
}

void AAStar_test2Character::AIMove()
{
	UE_LOG(LogTemp, Warning, TEXT("按下3,开始执行AIMOVE"));
	UWorld* World = GetWorld();
	if (!World) return;

	if (Maker == nullptr)
	{
		Maker = NewObject<UMyDelegateMaker>();
	}
    // 绑定并执行委托
	Maker->BindAIMove(World).Execute();
}

委托制造类(重点)

MyDelegateMaker.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "MyDelegateMaker.generated.h"

// 声明 委托/代理 类型
DECLARE_DELEGATE(FDelegateNoParam)
/**
 * 
 */
UCLASS()
class ASTAR_TEST2_API UMyDelegateMaker : public UObject
{
	GENERATED_BODY()

public:
    //定义委托变量
	FDelegateNoParam Delegate;
	FDelegateNoParam Delegate_AIMove;

    // 绑定委托函数
    
	// 绑定样条点设置 由于委托类并不存在于真实蓝图世界中,故其需要外部传入的world
	FDelegateNoParam& BindSpineSet(UWorld*  World);
	// 绑定AI移动
	FDelegateNoParam& BindAIMove(UWorld*  World);
	
	class ASpine* USpineRef = nullptr;

	class AMyAIController* AIControllerRef = nullptr;
	
};

MyDelegateMaker.cpp

#include "MyDelegateMaker.h"

#include "EngineUtils.h"
#include "MyAIController.h"
#include "Spine.h"
#include "Kismet/GameplayStatics.h"

FDelegateNoParam& UMyDelegateMaker::BindSpineSet(UWorld*  World)
{
	// 若已经绑定,则解绑
	if (Delegate.IsBound())
	{
		Delegate.Unbind();
	}
	
    // 
	if (USpineRef == nullptr)
	{
		if(World == nullptr)  {
			UE_LOG(LogTemp, Error, TEXT("World is nullptr"));
		}
		else
		{
			for (TActorIterator<ASpine> It(World); It; ++It)
			{
				USpineRef = *It;
				// 可添加if判断是否满足条件
			}
		}
		
	}
    // 绑定函数
	Delegate.BindUObject(USpineRef, &ASpine::setSpine);
	
	return Delegate;
}

FDelegateNoParam& UMyDelegateMaker::BindAIMove(UWorld* World)
{
	if (Delegate.IsBound())
	{
		Delegate.Unbind();
	}

	if (AIControllerRef == nullptr)
	{
		if (World)
		{
			for (TActorIterator<AMyAIController> It(World); It; ++It)
			{
				AIControllerRef = *It;
			}
			Delegate_AIMove.BindUObject(AIControllerRef, &AMyAIController::goAIMove);
		}
	}

	return Delegate_AIMove;
}

被调用类

该类中的方法主要是依据A星路线动态生成样条点,可以掠过不看,注意使用方法即可

Spine.h

	// 创建样条点路径
	UFUNCTION()
	void setSpine() const;

Spine.cpp

// 创建样条点路径
void ASpine::setSpine() const
{
	UWorld* World = GetWorld();
	
	// 获取样条组件
	USplineComponent* SplineComp = this -> FindComponentByClass<USplineComponent>();
	if (!SplineComp) return;

	// 获取样条点数组中所有点的位置
	APlayerController* PlayerController = UGameplayStatics::GetPlayerController(World, 0);
	if (!PlayerController) return;
	AAStar_test2Character* Character = Cast<AAStar_test2Character>(PlayerController->GetPawn());
	if (!Character) return;
	TArray<FVector> Vectors = Character->AllPositions;

	// 遍历所有位置并添加样条点
	for (const FVector& Position : Vectors)
	{
		SplineComp->AddSplinePoint(Position, ESplineCoordinateSpace::World);
	}

	// 更新样条
	SplineComp->UpdateSpline();
	
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值