UE5 C++ 通过绑定编辑器事件实现控制柄顶点编辑

开发中经常会遇到编辑器环境中制作工具拖拽控制柄编辑内容的需求,此时可以通过Editor事件拿到对应回调,进行相应更新:

1.创建Mesh编辑Actor类

创建一个Mesh编辑Actor类,提供Mesh顶点编辑的相关逻辑。

.h:

cpp 复制代码
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ProceduralMeshComponent.h"
#include "DraggableHandleActor.h"
#include "CustomMeshActor.generated.h"

UCLASS()
class MYPROJECT6_API ACustomMeshActor : public AActor
{
	GENERATED_BODY()
	
public:	
	ACustomMeshActor();

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	UProceduralMeshComponent* MeshComponent;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	ADraggableHandleActor* HandleP0;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	ADraggableHandleActor* HandleP1;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	ADraggableHandleActor* HandleP2;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	ADraggableHandleActor* HandleP3;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	void OnRebuild();

	UFUNCTION()
	void OnHandleP0Moved();

	UFUNCTION()
	void OnHandleP1Moved();

	UFUNCTION()
	void OnHandleP2Moved();

	UFUNCTION()
	void OnHandleP3Moved();
};

.cpp:

cpp 复制代码
#include "CustomMeshActor.h"

ACustomMeshActor::ACustomMeshActor()
{
	PrimaryActorTick.bCanEverTick = true;

	MeshComponent = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("ProceduralMesh"));
	RootComponent = MeshComponent;
}

void ACustomMeshActor::BeginPlay()
{
	Super::BeginPlay();
	
    HandleP0->OnHandleMoved.AddDynamic(this, &ACustomMeshActor::OnHandleP0Moved);
    HandleP1->OnHandleMoved.AddDynamic(this, &ACustomMeshActor::OnHandleP1Moved);
    HandleP2->OnHandleMoved.AddDynamic(this, &ACustomMeshActor::OnHandleP2Moved);
    HandleP3->OnHandleMoved.AddDynamic(this, &ACustomMeshActor::OnHandleP3Moved);

    this->OnRebuild();
}

void ACustomMeshActor::OnRebuild()
{
    TArray<FVector> Vertices;
    
    FTransform ActorTransform = GetActorTransform();

    Vertices.Add(HandleP0->GetActorLocation());
    Vertices.Add(HandleP1->GetActorLocation());
    Vertices.Add(HandleP2->GetActorLocation());
    Vertices.Add(HandleP3->GetActorLocation());

    TArray<int32> Triangles;
    Triangles.Add(0);
    Triangles.Add(1);
    Triangles.Add(2);

    Triangles.Add(0);
    Triangles.Add(2);
    Triangles.Add(3);

    // 定义 UV 坐标
    TArray<FVector2D> UV0;
    UV0.Add(FVector2D(0.0f, 0.0f));
    UV0.Add(FVector2D(0.0f, 1.0f));
    UV0.Add(FVector2D(1.0f, 1.0f));
    UV0.Add(FVector2D(1.0f, 0.0f));

    // 法线
    TArray<FVector> Normals;
    Normals.Add(FVector(0.0f, 0.0f, 1.0f));
    Normals.Add(FVector(0.0f, 0.0f, 1.0f));
    Normals.Add(FVector(0.0f, 0.0f, 1.0f));
    Normals.Add(FVector(0.0f, 0.0f, 1.0f));

    // 切线
    TArray<FProcMeshTangent> Tangents;
    Tangents.Add(FProcMeshTangent(1.0f, 0.0f, 0.0f));
    Tangents.Add(FProcMeshTangent(1.0f, 0.0f, 0.0f));
    Tangents.Add(FProcMeshTangent(1.0f, 0.0f, 0.0f));
    Tangents.Add(FProcMeshTangent(1.0f, 0.0f, 0.0f));

    TArray<FColor> VertexColors;
    VertexColors.Add(FLinearColor::White.ToFColor(true));
    VertexColors.Add(FLinearColor::White.ToFColor(true));
    VertexColors.Add(FLinearColor::White.ToFColor(true));
    VertexColors.Add(FLinearColor::White.ToFColor(true));

    MeshComponent->ClearAllMeshSections();
    MeshComponent->CreateMeshSection(0, Vertices, Triangles, Normals, UV0, VertexColors, Tangents, true);
}

void ACustomMeshActor::OnHandleP0Moved()
{
    OnRebuild();
}

void ACustomMeshActor::OnHandleP1Moved()
{
    OnRebuild();
}

void ACustomMeshActor::OnHandleP2Moved()
{
    OnRebuild();
}

void ACustomMeshActor::OnHandleP3Moved()
{
    OnRebuild();
}

这部分代码通过UE的ProceduralMeshComponent动态创建顶点和Mesh。

2.创建操作柄

第二步需要实现拖拽操作柄或者修改界面数值得到回调,从而更新Mesh,在UE中这一块的编辑器回调有如下:

cpp 复制代码
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; //UE面板修改数值
virtual void PostEditMove(bool bFinished) override; //UE界面拖拽Actor

接下来编写Actor - DraggableHandleActor来实现这样的逻辑:

.h

cpp 复制代码
#pragma once

#include "CoreMinimal.h"
#include "DraggableHandleActor.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnHandleMoved);

UCLASS()
class MYPROJECT6_API ADraggableHandleActor : public AActor
{
    GENERATED_BODY()

public:
    ADraggableHandleActor();

#if WITH_EDITOR
    virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
    virtual void PostEditMove(bool bFinished) override;
#endif
    // Delegate for handle moved callback
    UPROPERTY(BlueprintAssignable, Category = "Handle Events")
    FOnHandleMoved OnHandleMoved; // Delegate for broadcasting the movement
};

.cpp:

cpp 复制代码
#include "DraggableHandleActor.h"

ADraggableHandleActor::ADraggableHandleActor()
{
}

#if WITH_EDITOR

void ADraggableHandleActor::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
    Super::PostEditChangeProperty(PropertyChangedEvent);

    OnHandleMoved.Broadcast();
}

void ADraggableHandleActor::PostEditMove(bool bFinished)
{
    Super::PostEditMove(bFinished);

    OnHandleMoved.Broadcast();
}

#endif

注意这里定义了一个委托来给外部绑定回调:

cpp 复制代码
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnHandleMoved);

3.UE整合

最后在UE中绑定控制柄对应的Actor,并放置进对应的UMG或者Editor触发代码中即可。最后再记录顶点操作位置,再在运行时还原,即可实现这样的编辑器下顶点修改编辑需求。

相关推荐
FQNmxDG4S2 小时前
Java多线程编程:Thread与Runnable的并发控制
java·开发语言
前端老石人2 小时前
HTML 字符引用完全指南
开发语言·前端·html
matlab_xiaowang3 小时前
Redux 入门:JavaScript 可预测状态管理库
开发语言·javascript·其他·ecmascript
虹科网络安全3 小时前
艾体宝干货|数据复制详解:类型、原理与适用场景
java·开发语言·数据库
axng pmje3 小时前
Java语法进阶
java·开发语言·jvm
汉克老师3 小时前
GESP2025年3月认证C++五级( 第三部分编程题(1、平均分配))
c++·算法·贪心算法·排序·gesp5级·gesp五级
老前端的功夫3 小时前
【Java从入门到入土】28:Stream API:告别for循环的新时代
java·开发语言·python
qq_435287923 小时前
第9章 夸父逐日与后羿射日:死循环与进程终止?十个太阳同时值班的并行冲突
java·开发语言·git·死循环·进程终止·并行冲突·夸父逐日
止语Lab4 小时前
从手动到框架:Go DI 演进的三个拐点
开发语言·后端·golang
yaoxin5211234 小时前
397. Java 文件操作基础 - 创建常规文件与临时文件
java·开发语言·python