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触发代码中即可。最后再记录顶点操作位置,再在运行时还原,即可实现这样的编辑器下顶点修改编辑需求。

相关推荐
景天科技苑2 分钟前
【Golang】Go语言中如何进行包管理
开发语言·后端·golang·go mod·go语言包管理·go包管理·go sum
wwangxu5 分钟前
Java 面向对象基础
java·开发语言
wdxylb20 分钟前
Linux下编写第一个bash脚本
开发语言·chrome·bash
幽兰的天空23 分钟前
Python实现的简单时钟
开发语言·python
这题怎么做?!?30 分钟前
模板方法模式
开发语言·c++·算法
程序员yt1 小时前
2025秋招八股文--服务器篇
linux·运维·服务器·c++·后端·面试
幽兰的天空1 小时前
简单的Python爬虫实例
开发语言·爬虫·python
Chris-zz1 小时前
Linux:磁盘深潜:探索文件系统、连接之道与库的奥秘
linux·网络·c++·1024程序员节
冷眼看人间恩怨1 小时前
【Java】揭秘网络编程:深入探索其无尽奥秘与魅力
java·开发语言·tcp/ip·udp·tcp
※※冰馨※※1 小时前
Unity3D 鼠标移动到按钮上显示信息
开发语言·unity·c#