UE5-C++入门教程(二)---编写Editor类别的自定义模型实现小球规划路线的可视化

前言


1.基本概念:模板和插件

  • *Modules(模块): 在Unreal Engine中,模块是引擎功能的基本构建块。每个模块封装了一组相关的功能,如渲染、物理、动画、音频等。模块可以是系统级别的,也可以是项目级别的。系统级别的模块通常是引擎的一部分,而项目级别的模块则专门为特定项目定制。

    • 模块可以包含C++源代码、头文件、蓝图文件、配置文件、资源文件等。开发者可以通过添加、修改或删除模块来定制Unreal Engine的功能。模块的这种结构允许开发者只包含他们项目所需的组件,从而优化性能和资源使用。
    • 上次教程我们创建的UE5Turtorial项目就是一个Module请添加图片描述
  • *Plugins(插件): 插件是Unreal Engine中的一个特殊类型的模块,它允许开发者在不修改引擎源代码的情况下添加或扩展功能。插件可以是Epic Games提供的,也可以是第三方开发者创建的。插件通常包含一个或多个模块,它们被打包在一起,可以轻松地在不同的项目之间共享。

    • 插件可以提供从视觉效果到游戏逻辑的各种功能。开发者可以通过Unreal Engine的插件市场下载和安装插件,也可以创建自己的插件并将其分享给其他人。

2.创建自定义模块

2-1 为项目介绍模块–修改.uproject
  • 由于反复进退ue5并且进行重复编译调试连接很麻烦,这里提出一个书写自定义模块的方式,下面我们来不借助编译器和UE5,手动为项目添加一个模块

  • 这里我们随便使用一个编辑器打开你的项目根目录,这里我使用的是VScode

  • 找到项目工程文件夹Source文件夹下你的项目模块,找到你项目的.uproject文件请添加图片描述

  • 找到模组

    • Type用于指定模型的类型,这里介绍两种今天我们会用上的
      • Runtime Module运行时模块是在游戏运行时加载的模块,它们包含游戏逻辑、游戏模式、关卡脚本等。这些模块在游戏启动时加载,并在游戏运行期间保持活动状态。
      • Editor Module:编辑器模块是专门为Unreal Engine编辑器设计的模块,它们包含编辑器工具、自定义资产类型、编辑器扩展等。这些模块只在编辑器中加载和使用。
    • LoadingPhase定义了模块加载的时机。
      • Default:这是默认的加载阶段,模块在引擎初始化后加载。
      • PreLoadingScreen:模块在加载屏幕显示之前加载,通常用于初始化需要快速完成的任务。
      • PostEngineInit:模块在引擎初始化完成后加载,通常用于执行需要引擎完全初始化后才能进行的任务。
"Modules": [
	{
		"Name": "UE5Tutorial",
		"Type": "Runtime",
		"LoadingPhase": "Default",
		"AdditionalDependencies": [
			"Engine"
		]
	}
],
  • 创建一个自定义模组,设定为Editor
{
	"Name": "UE5TutorialEditor",
	"Type": "Editor",
	"LoadingPhase": "PostEngineInit"
}

2-2 为模块添加到编译组中
  • 然后找到Source目录下的.Target.cs文件,添加我们新的模块"UE5TutorialEditor.Target.cs"
// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;
using System.Collections.Generic;

public class UE5TutorialEditorTarget : TargetRules
{
	public UE5TutorialEditorTarget( TargetInfo Target) : base(Target)
	{
		Type = TargetType.Editor;
		DefaultBuildSettings = BuildSettingsVersion.V5;
		IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_4;
		ExtraModuleNames.Add("UE5Tutorial");
	}
}
  • 添加我们的新模块
//ExtraModuleNames.Add("UE5Tutorial");
ExtraModuleNames.AddRange(new string[] { "UE5Tutorial", "UE5TutorialEditor" });

  • 紧接着我们为新的模块创建一个新的文件夹,注意需要和模块名同名UE5TutorialEditor,并把我们原本项目文件夹下的UE5Tutorial.Build.cs拷贝一份到新的自定义模块的文件夹下,并改名为UE5TutorialEditor.Build.cs请添加图片描述

  • 然后我们打开UE5TutorialEditor.Build.cs,把里头对应的类名修改,并将"UnrealEd","UE5Tutorial"添加至依赖中

    • "UnrealEd" 模块指的是Unreal Engine的编辑器模块。
    • "UE5Tutorial"模块是我们上一节写的移动小球的模块
// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class UE5TutorialEditor : ModuleRules
{
	public UE5TutorialEditor(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput","UnrealEd","UE5Tutorial"});

		PrivateDependencyModuleNames.AddRange(new string[] {  });

		// Uncomment if you are using Slate UI
		// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
		
		// Uncomment if you are using online features
		// PrivateDependencyModuleNames.Add("OnlineSubsystem");

		// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
	}
}

2-3 实现模块类–继承自IModuleInterface
  • IModuleInterface 是一个接口,它定义了一个模块与其他模块或系统交互的标准方式。这个接口允许模块提供一组功能,这些功能可以在模块被加载后由其他模块调用,而不需要直接引用模块的内部实现。

  • IModuleInterface 的主要目的是为了实现模块之间的解耦,使得模块可以独立地开发、测试和更新,同时仍然能够与其他模块进行交互。通过实现 IModuleInterface,一个模块可以公开一组函数,这些函数可以被其他模块在需要时调用。

  • 我们创建如下两个文件
    请添加图片描述

  • UE5TutorialEditor.hpp

#pragma once

#include "Engine.h"
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"
#include "UnrealEd.h"

DECLARE_LOG_CATEGORY_EXTERN(UE5TutorialEditor,All,All)

class FUE5TutorialEditorModule:public IModuleInterface
{
//public:
	//virtual void StartupModule()override;
	//virtual void ShutdownModule()override;
};
  • UE5TutorialEditor.cpp
#include "UE5TutorialEditor.h"
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"

#include "UnrealEd.h"


IMPLEMENT_GAME_MODULE(FUE5TutorialEditorModule, UE5TutorialEditor);

2-4 编译
  • 回到VS2022,点击绿色透明箭头,开始构建项目,我们会发现代码新的模块的库被创建请添加图片描述

  • 在新开的UE中刷新VS2022请添加图片描述

  • VS2022就有新的模块被添加进来了请添加图片描述

  • 如果有报错,请检查代码拼写,不要漏掉了;或者拼错了函数


2-5 检查

  • 在菜单栏的工具找到调试选择模块请添加图片描述

  • 可以看到我们的模块已经被添加进来请添加图片描述


3.创建自定义可视化UI的ComponentVisualizer

  • 工具里我们新建一个C++类(具体方式上一节我们讲过,这里快速略过)
3-1 创建可视化类
  • 我们创建一个Empty的FMoveComponentVisualizer类,继承自FComponentVisualizer

    • FComponentVisualizer 是 Unreal Engine (UE) 中的一个类,它用于在 UE 编辑器中可视化场景中的组件。组件(Components)是 UE 中的一个核心概念,代表游戏对象(Actors)上的各种功能,如静态网格、骨骼网格、相机、灯光等。
    • FComponentVisualizer 类用于在编辑器中绘制组件的可视表示,这通常包括组件的边界框、碰撞体、骨骼等。开发人员可以使用这个类来创建自定义的可视化效果,以便更好地理解组件在场景中的位置和方向。
  • 这里我们实现基类的虚函数DrawVisualization请添加图片描述

    • const UActorComponent* Component: 指向要绘制的组件的指针。这是一个常量指针,意味着你不会在这个函数中修改组件的状态。
    • const FSceneView* View: 指向当前场景视图的指针。场景视图包含了渲染场景所需的所有信息,如相机设置、视口大小等。这也是一个常量指针。
    • FPrimitiveDrawInterface* PDI: 指向用于绘制原语(primitives)的接口的指针。原语可以是线、点、三角形等,用于在 3D 空间中绘制形状。通过这个接口,你可以添加自定义的绘制调用到场景中。
  • FMoveComponentVisualizer.hpp

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "ComponentVisualizer.h"
#include "UE5Tutorial/MoveComponent.h"
/**
 * 
 */
class UE5TUTORIALEDITOR_API FMoveComponentVisualizer: public FComponentVisualizer
{
public:
	void DrawVisualization(const UActorComponent* Component,const FSceneView*View,FPrimitiveDrawInterface* PDI )override;
};
  • FMoveComponentVisualizer.cpp
    • 这里我们获取UMoveComponent,如果存在,我们就绘制一条线,起点和终点分别是小球的起点和终点
// Fill out your copyright notice in the Description page of Project Settings.


#include "MoveComponentVisualizer.h"

void FMoveComponentVisualizer::DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI)
{
	const UMoveComponent* MoveComponent = Cast<UMoveComponent>(Component);
	if (MoveComponent)
	{
		PDI->DrawLine(
			MoveComponent->StartRelativeLocation,
			MoveComponent->EndRelativeLocation,
			FLinearColor::Red,
			SDPG_Foreground,
			5.0f
			);
	}
}
  • 由于小球的StartRelativeLocationEndRelativeLocation属性是private的,这里我们需要为UMoveComponent添加友元FMoveComponentVisualizer,打开MoveComponent.cpp,添加友元
private:
	friend class FMoveComponentVisualizer;
	FVector StartRelativeLocation;
	UPROPERTY(EditAnywhere)
	float speed=1.0f;
	UPROPERTY(EditAnywhere)
	FVector EndRelativeLocation;
	FVector CurrentLocation;
	float stoppingDistance = 1.0f;
3-2 注册模型编辑可视化
  • 我们需要在编辑器中注册和注销一个自定义的组件可视化器 FMoveComponentVisualizer
  • UE5TutorialEditorModule.hpp
#pragma once

#include "Engine.h"
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"
#include "UnrealEd.h"

#include "MoveComponentVisualizer.h"
DECLARE_LOG_CATEGORY_EXTERN(UE5TutorialEditor,All,All)

class FUE5TutorialEditorModule:public IModuleInterface
{
public:
	void StartupModule()override;
	void ShutdownModule()override;
};
  • UE5TutorialEditorModule.cpp
    • 首先检查 GUnrealEd(全局编辑器指针)是否有效。
    • 如果有效,它会创建一个新的 FMoveComponentVisualizer 实例,并使用 MakeShareable 函数将其转换为共享指针。
    • 它注册这个可视化器,以便它可以在编辑器中用于 UMoveComponent 类型的组件。
#include "UE5TutorialEditor.h"
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"

#include "UnrealEd.h"


IMPLEMENT_GAME_MODULE(FUE5TutorialEditorModule, UE5TutorialEditor);
void FUE5TutorialEditorModule::StartupModule()
{
	if (GUnrealEd)
	{
		TSharedPtr<FMoveComponentVisualizer> MoveVisualizer = MakeShareable(new FMoveComponentVisualizer);
		if (MoveVisualizer.IsValid())
		{
			GUnrealEd->RegisterComponentVisualizer(UMoveComponent::StaticClass()->GetFName(), MoveVisualizer);
			MoveVisualizer->OnRegister();
		}

	}

}
void FUE5TutorialEditorModule::ShutdownModule()
{
	if (GUnrealEd)
	{
		GUnrealEd->UnregisterComponentVisualizer(UMoveComponent::StaticClass()->GetFName());


	}

}
3-3 编译
  • 我们在调试的模块中找到我们的模块,点击重新编译请添加图片描述

  • 点开输出日志,不出意料的报错了,根据报错提示请添加图片描述

  • 我们关闭实时代码编译请添加图片描述

  • 重新点击重新编译请添加图片描述


4. 结果展示

  • 我们修改Move组件的目标位置,可以发现线也随之改变请添加图片描述

  • 请添加图片描述

  • 值得一提的是,整个过程中我们不需要编译整个项目,也不需要进行仿真,这为我们进行代码调试时非常方便的。

  • 此外这条调试线将在开始仿真的时候会消失,因为这是供我们编译模型下使用,后续我们会介绍如何在运行过程中可视化


小结

  • 本节我们介绍了如何自定义module,并添加了一个Editor的模型,使我们可以在不编译整个项目不开启仿真的前提下可视化小球的规划路线。
  • 感谢大家对本教程的支持,如有错误,欢迎指出。
  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: realcity智慧城市可视化案例教程-ue5制作,是一款非常实用的城市规划设计软件,可以帮助城市规划师在城市规划过程中提高效率,节约设计成本,改善城市形象和居民生活质量。 本教程使用ue5引擎进行制作,不仅具有强大的创作工具和渲染效果,还可以实时编辑和模拟城市场景,方便快捷地进行可视化呈现和修改。 在使用realcity智慧城市可视化案例教程-ue5制作进行城市规划设计时,可以先对城市区域进行分析和分类,在制定城市规划方案之前,需要考虑以下几个因素:城市交通、建筑布局、绿化环境、人口分布、公共设施、自然资源等。 通过合理的规划和设计,可以实现节约用地、提高城市通行性、增加城市景观、提高公共设施和城市安全等多个目标。 总之,realcity智慧城市可视化案例教程-ue5制作是一款非常实用的城市规划设计软件,可以为城市规划师提供全面的数据支持和交互式的建模平台,从而实现一流的城市规划设计效果。 ### 回答2: realcity智慧城市可视化案例教程-ue5制作是一门针对城市规划可视化方面的教程,主要介绍了如何使用UE5软件进行城市场景的制作和展示。在这个教程中,学员可以学习到如何通过UE5软件绘制城市的形状、建筑、地形等,然后通过添加各种元素来制作一个真实、逼真的城市场景。这个教程不仅让学员了解了城市规划和设计的理论,还让他们掌握了实际操作技巧。 这个教程的核心是通过UE5软件展示智慧城市的相关信息,例如:交通状况、城市规划、人口密度等,通过实时的可视化呈现,让人们更直观地了解和感受智慧城市的优势。 通过这个教程,学员可以了解到如何将城市数据转化为可视化的形式,并利用UE5软件提供的高级功能,例如光影、材质、粒子特效等,来创造出一个完美的城市场景。同时,这个教程也说明了如何为城市场景添加交互功能,例如地图搜索、路线规划等。 总之,realcity智慧城市可视化案例教程-ue5制作是一门非常实用的教程,不仅可以帮助城市规划和设计从业人员提升技能水平,还可以为城市决策者提供更直观和可靠的数据支持,帮助建设更加智慧、高效的城市。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值