为Unity开发者准备的虚幻引擎指南 您所在的位置:网站首页 用vs编写c程序如何运行 为Unity开发者准备的虚幻引擎指南

为Unity开发者准备的虚幻引擎指南

2023-05-17 16:28| 来源: 网络整理| 查看: 265

相关课程 从Unity到虚幻引擎 虚幻引擎入门:第一个小时 虚幻引擎入门 UE编辑器基础-编辑器入门 本页面的内容

虚幻编辑器

编辑资产

术语简表

项目和文件

怎么理解虚幻引擎项目的常用文件和目录?

我的资产应该放在哪里?

支持哪些文件格式?

如何保存场景?

如何修改项目设置?

源文件在哪里?

从GameObject到Actor

GameObject在哪里?

组件在哪里?

从Unity的Prefab到虚幻引擎的蓝图类

Unity中的Script组件和MonoBehaviour去哪里了?

可编写脚本的Actor蓝图类

蓝图类可以扩展

那么应该用蓝图脚本还是C++代码呢?或者同时使用?

蓝图类可以扩展C++类

变换组件

复合对象

我需要用组件构建一切吗?

那么一切都是Actor吗?

虚幻引擎中的Gameplay框架是什么?

在虚幻引擎中编写代码

写给C++程序员

编写事件函数(Start、Update等)

在虚幻引擎中编写游戏逻辑代码

实例化GameObject/生成Actor

类型转换

销毁GameObject/Actor

销毁GameObject/Actor(延迟1秒)

禁用GameObject/Actor

从组件访问GameObject/Actor

从GameObject/Actor访问组件

查找GameObject/Actor

向GameObject/Actor添加标签

向MonoBehaviour/ActorComponent添加标签

比较GameObject/Actor和MonoBehaviour/ActorComponent上的标签

物理:刚体与图元组件

层与通道

RayCast与RayTrace

触发器体积

刚体运动

输入事件

常见问题解答

如何自动加载最后一个项目?

哪里可以设置游戏的输入绑定?

如何更改项目的初始场景?

如何运行游戏?

虚幻引擎使用什么测量单位?

在虚幻引擎的坐标系中,哪个方向朝上?

如何查看游戏的输出日志?

如何抛出异常?

.NET Framework在哪里?

代码更改时虚幻引擎是否会自动重新加载?

查找帮助和答案

本页面为熟悉Unity的用户概述了 虚幻引擎(UE)。如果你具备一些Unity知识,而且想学习如何运用自己所学的知识在虚幻引擎中工作,下面各小节将帮助你入门。

虚幻编辑器

虚幻编辑器(Unreal Editor) 是你处理虚幻引擎项目的地方。下面的截图并排显示了Unity和虚幻编辑器。各个区域采用相同的颜色来表示相同的功能。每个区域上还添加了名称,以便你了解它们在虚幻引擎语境中的称呼。

虚幻编辑器支持自定义布局。你可以拖放选项卡、将其停靠到主窗口中、更改颜色方案,等等。

unity-to-unreal-engine-ui-comparison.png

Unity和虚幻引擎5主界面元素的直观对比。点击查看大图。

编辑资产

在Unity中,你使用 Inspector 选项卡来编辑项目中的所选资产。在虚幻编辑器中,细节(Details) 面板公开所选资产的属性。比较复杂的资产编辑工作则在专门的编辑器窗口中处理,你可以将这些窗口停靠到主UE窗口中,或拖动到桌面上的其他地方(例如,拖到第二个显示器)。

unreal-engine-tabbed-editors.png

虚幻编辑器中的选项卡式编辑器。关卡编辑器(Level Editor) 在背景中,而 材质编辑器(Material Editor) 目前处于活动状态。

如需虚幻引擎中各种资产编辑器的一般简介,请参阅工具和编辑器页面。

术语简表

下表左侧是Unity中常见术语,右侧则是对应的(或近似的)虚幻引擎术语。虚幻引擎(Unreal Engine) 列中的每个术语都链接到专门的页面,你可以前往这些页面了解详情。

类别

Unity

虚幻引擎

Gameplay类型

Component

组件

GameObject

Actor

Prefab

蓝图类

编辑器界面

Hierarchy Panel

世界大纲视图

Inspector

细节面板

Project Browser

内容浏览器

Scene View

关卡视口

网格体

Mesh

静态网格体

Skinned Mesh

骨骼网格体

材质

Shader

材质、材质编辑器

Material

材质实例

特效

Particle Effect

特效、粒子、Niagara

游戏界面

UI

UMG(虚幻示意图形)

动画

Animation

骨骼网格体动画系统

Mecanim

动画蓝图

Sequences

Sequencer

2D

Sprite Editor

Paper2D

编程

C#

C++

Script、Bolt

蓝图

物理

Raycast

Line Trace、Shape Trace]

Rigidbody

碰撞、物理

运行时平台

iOS Player、Web Player

支持的平台

项目和文件 怎么理解虚幻引擎项目的常用文件和目录?

和Unity项目一样,虚幻项目也保存在专门的目录结构中,并且有自己的项目文件,扩展名为 .uprojectfile 。你可以 双击 .uproject 文件,将游戏加载到虚幻编辑器中,或 右键点击 查看更多选项。

项目目录包含不同子目录,保存了游戏的资产内容和源代码,以及各种配置文件和二进制文件。其中最重要的就是 Content 文件夹和 Config 文件夹,前者保存项目的所有资产,后者保存项目的配置(.ini)文件。

我的资产应该放在哪里?

在虚幻引擎中,每个项目都有一个 Content 文件夹。这类似于Unity项目的 Assets 文件夹,是你保存游戏资产的地方。

如果你的虚幻引擎项目包含C++类,它们将位于项目在磁盘上的 Source 文件夹。

要将资产导入游戏中,请通过内容浏览器将文件放入项目的 Content 目录。

如需详细了解资产导入过程,请参阅直接导入资产页面。

支持哪些文件格式?

虚幻引擎5支持一些最常见的文件类型:

资产类型

支持的格式

3D

.fbx、.obj

纹理

.png、.jpeg、.bmp、.tga、.dds、.exr、.psd、.hdr

声音

.wav

字体

.ttf、.otf

视频

.mov、.mp4、.wmv

此外,你可以使用专用插件导入其他类型的内容,例如:

插件

支持的内容

Datasmith

3ds Max、SketchUp、Revit等各种CAD应用程序中的3D场景和资产

LiDAR点云插件

LiDAR点云。请参阅LiDAR点云插件概述,查看支持的文件类型列表。

USD导入器

.usd(通用场景描述)

Alembic文件导入器

.abc

如何保存场景?

在Unity中,你将GameObject放在场景中,然后将其保存为场景资产文件。 虚幻引擎使用 贴图文件(Map file) ,它类似于Unity中的场景。 贴图文件保存了 关卡 的数据、关卡中对象、光照数据和某些关卡特定的设置信息。

如何修改项目设置?

从虚幻编辑器的主菜单,转至 编辑(Edit)> 项目设置(Project Settings) 。

就像Unity的项目设置,这些设置可实现以下功能:

控制项目的相关信息,例如项目名称和图标。

配置游戏输入绑定。

定义引擎在运行项目时的行为表现。

等等。

如需详细了解 项目设置(Project Settings) 窗口,请参阅Project Settings 页面。

Unity还有叫做"玩家设置(Player Settings)"的部分。在虚幻引擎中,我们叫 平台设置(Platform Settings) ,你可以在 项目设置(Project Settings) 窗口的 平台(Platforms) 分段下配置。

源文件在哪里?

在Unity中,你将C#源文件放在 Assets 文件夹中。在虚幻引擎中,你的源文件放在不同的位置,具体取决于你创建的虚幻项目的类型:

C++项目 在虚幻项目目录中有一个 Source 文件夹。Source 文件夹包含各种文件,包括C++源文件(.cpp)和头文件(.h),以及一些编译用的脚本(Build.cs、Target.cs)。

蓝图项目 没有 Source 文件夹。蓝图可以放在虚幻项目的 Content 文件夹中的任意位置。

如果你想将C++代码添加到蓝图项目,请从虚幻编辑器的主菜单转至 工具(Tools)> 新C++类(New C++ Class) 。

在 内容浏览器(Content Browser) 中双击C++源文件,可以在Visual Studio(Windows)或Xcode(macOS)中打开。

从GameObject到Actor GameObject在哪里?

在Unity中,GameObject是可以放在世界中的"东西"。虚幻引擎中对应的概念是 Actor 。在虚幻编辑器中,你可以从 主工具栏(Main Toolbar) 中的 创建(Create) 菜单将新的空Actor拖入视口中,如下所示:

你虽然可以通过空Actor来制作游戏,但虚幻引擎还提供了各类特殊的Actor,并预置了它们的特性,例如 Pawn(用于可以由玩家或AI控制的Actor),或 角色(用于需要复杂移动和交互的可控制玩家角色)。就像空Actor那样,你可以将这些特殊类型的Actor放入视口中,然后添加或自定义其属性和组件。

虚幻引擎有一种Gameplay框架来处理这些特殊Actor。你将在后面详细了解Gameplay框架。

虚幻引擎中的Actor与Unity中的GameObject稍有不同。在Unity中,GameObject是C#类,不能直接扩展。在虚幻引擎中,Actor是C++类,可以使用继承来扩展和自定义。下文会详细介绍继承的概念。

组件在哪里?

在Unity中,你使用组件向GameObject添加功能。在虚幻引擎中,你将组件添加到Actor。你在关卡中放入空Actor之后,将其选中,然后点击 细节(Details) 面板中的 添加组件(Add Component) 按钮,然后选择要添加的组件。

在下面的视频中,我们会创建一把火炬,首先放入一个空Actor,然后添加一个网格体组件作为基座,接着添加光源和粒子系统来创建火焰。

在Unity中,GameObject以列表形式保存组件。在虚幻引擎中,Actor以 层级(Hierarchy) 形式保存组件,而且组件之间相互绑定。你可以在以上示例中看到,光源和粒子与静态网格体相互绑定。这会带来一些重要的影响,本页面的 复合对象 小节会进行说明。

从Unity的Prefab到虚幻引擎的蓝图类

在Unity中,你使用组件构建一组GameObject,然后从中创建预制件(prefab)。接着,你可以在世界中放入预制件的实例,或在运行时将其实例化。

虚幻引擎有相同类型的工作流程,但其基于蓝图类:

1.使用组件构建Actor。

在Actor的 细节(Details) 面板中,点击 蓝图(Blueprint)> 添加脚本(Add Script) ,向其添加蓝图。

选择一个位置保存你的新蓝图类。

点击 创建蓝图(Create Blueprint) 。

这样就可以了!

你可以从 内容浏览器(Content Browser) 访问新蓝图类。双击 可直接编辑,或将其拖入打开的关卡以放入游戏世界中。

Unity中的Script组件和MonoBehaviour去哪里了?

在Unity中,你通过将脚本组件放在GameObject上来添加C#脚本。你通过创建从MonoBehaviour继承的类来定义该组件的功能。

虚幻引擎的工作方式相同:你可以使用蓝图或C++创建全新的组件类,并将其添加到任意Actor。类似于将蓝图添加到Actor,你可以通过以下两种方式之一将组件添加到Actor:

从Actor的 细节(Details) 面板。

从 编辑Actor(Edit Actor) 窗口。

将新组件添加到Actor的步骤如下:

从Actor的 细节(Details) 面板或 编辑Actor(Edit Actor) 窗口,点击 添加组件(Add Component) 。

选择要添加到Actor的组件。你可以创建新组件,或从预定义组件列表中选择,例如光源、音频、粒子系统,等等。

将组件添加到Actor

在Unity中,创建新的MonoBehaviour时,你会收到一个骨架类文件,其中包含 Start() 函数和 Update() 函数。

在虚幻引擎中,新组件有类似的函数:

InitializeComponent(),其作用与Unity的 Start()` 函数相同。

TickComponent(),其作用与Unity的 Update()` 函数相同。

在蓝图组件中,这些函数显示为可视化节点。

可编写脚本的Actor蓝图类

你的新Actor蓝图类会有自己的蓝图可视化脚本。这样一来,你就可以将逻辑添加到整个对象,而不仅仅是单个组件。结合继承结构关系(稍后下文会解释),这会为你在设计游戏时提供很多灵活性。

除了支持可视化脚本的蓝图类之外,虚幻引擎还支持使用代码来实现C++类。下面并排比较了Unity和虚幻引擎代码,还给出了具有相同作用的虚幻引擎蓝图。

Unity C#

using UnityEngine; using System.Collections; public class MyComponent : MonoBehaviour { int Count; // 此函数来初始化。 void Start () { Count = 0; } // Update函数会每帧调用一次。 void Update () { Count = Count + 1; Debug.Log(Count); } }

虚幻引擎C++

#pragma once #include "GameFramework/Actor.h" #include "MyActor.generated.h" UCLASS() class AMyActor : public AActor { GENERATED_BODY() int Count; // 为此Actor的属性设置默认值。 AMyActor() { // 允许调用Tick() PrimaryActorTick.bCanEverTick = true; } // 在游戏开始时或Actor生成时调用。 void BeginPlay() { Super::BeginPlay(); Count = 0; } // 每帧调用。 void Tick(float DeltaSeconds) { Super::Tick(DeltaSeconds); Count = Count + 1; GLog->Log(FString::FromInt(Count)); } };

蓝图

(image_28.png)

蓝图类可以扩展

类似于Unity的prefab,你也可以在虚幻引擎中将蓝图类实例化。

在虚幻引擎中,你可以创建新的蓝图类,它会扩展现有蓝图类,并使用新属性、组件和可视化脚本功能来增强。

例如,你可以创建名为Monster的蓝图类,用它实现基本的怪物功能,例如追击人类。然后,你可以再创建一个蓝图类来扩展它,例如Dragon(会喷火的怪物)、Grue(只在夜晚出没的怪物),以及其他8种类型,用来代表不同种类的怪物。Monster的所有这些子类都从Monster继承基本功能,并且还具备自己的新特征和能力。

在Unity中,你需要创建许多不同的GameObject prefab才能实现这点:你要为Dragon创建一个,为Grue创建一个,等等。现在,假设你要向所有怪物添加某种新功能,例如添加一个说话组件来让他们说话。在Unity中,你需要更新所有10个prefab,逐一将新功能复制粘贴到其中。

在虚幻引擎中,你只需修改Monster蓝图类,即可添加说话能力。这样就可以了!Dragon、Grue以及其他所有8个Monster子类将自动继承新的说话功能;你不需要逐一修改。

本小节中的所有内容也都适用于C++类,以及Actor和组件。这些系统从设计之初就能支持大规模开发可扩展功能,可以为10个开发人员的项目服务,也可以为100个人的项目服务。

那么应该用蓝图脚本还是C++代码呢?或者同时使用?

蓝图可视化脚本非常适合简单的游戏内逻辑和按顺序进行的事件。这个系统对策划、美术以及面向可视化编程的程序员是非常好用的,它能以可视化的方式轻松访问并管理游戏内对象。你完全可以仅凭蓝图完成一个独立小游戏的制作,以及打造其他互动式体验。

C++编程适合用于大型任务,例如编写某个游戏逻辑系统、制造复杂的AI行为、新增引擎功能。对于已经掌握了C++技能的开发人员来说,可参阅C++编程页面,详细了解虚幻引擎中的C++编程。

大部分项目都适合混合使用蓝图和C++。许多开发人员使用蓝图来创作游戏作原型,因为使用蓝图很容易制作原型和迭代,但之后之后出于性能优化、项目优化等考量,他们会改用C++完成部分或全部工作。

蓝图类可以扩展C++类

虚幻引擎游戏开发中很多令人着迷的过程存在于程序员用C++实现新的功能,而策划和美术可以在蓝图中测试这些新功能,以便给出切合实际的反馈。下图是针对一个UE的射击游戏项目中实现拾取物品过程时,团队的一种形式,混合了C++类的系统编程实现,以及蓝图类用于处理行为和表现。

虚幻引擎中的类继承

变换组件

在Unity中,每个GameObject都有一个变换组件,用于指定该GameObject在世界中的位置、旋转和比例。

虚幻引擎也一样,Actor有 根组件(Root Component),可以作为场景组件的任意子类。场景组件(Scene Component) 指定了Actor在世界中的位置、旋转和比例,这些属性也应用于以该场景组件为父节点的所有组件。很多有用的组件都是场景组件的子类,因此让它们具有位置信息是非常有用的!

即使你放置一个空Actor,虚幻引擎也会为该Actor创建默认场景根(Default Scene Root),这是一个最简单的场景组件。如果你放入新的场景组件,它将替换默认场景根。

复合对象

在Unity中,你可以通过构建GameObject层级以及绑定它们的变换组件来创建复合对象。

Unity GameObject关系

在虚幻引擎中,你可以通过让组件按照层级关系相互嵌套,来创建复合游戏对象。

虚幻引擎Actor和组件关系

如图所示,你可以让场景组件互相附加来得到一个相互嵌套的层级关系,因为它们有变换,这类似于Unity中的变换绑定。Actor组件(所有组件的基类)只能直接绑定到Actor本身。

我需要用组件构建一切吗?

这完全取决于你自己!通常,你应该是结合使用自定义组件类型,以及使用这些组件的Actor类。如前所述,虚幻引擎有许多特殊类型的Actor,它们附带一定的功能,并始终包含特定组件。例如,角色(Character) 始终包含 角色移动组件(Character Movement Component) 。

下面是一些常用的虚幻引擎Actor:

Pawn - 一种Actor,用于表示可控制的游戏对象,比如玩家操控的角色。玩家和AI都可以通过所属控制器移动Pawn。

角色(Character) - 一种版本更特殊的Pawn,用于双足类型的角色(角色有类似于人类的骨骼结构,用两条腿行走)。

控制器(Controller) - 占有并控制Pawn。通过将Pawn与控制器分离,你可以编写AI控制器,用于控制Pawn,并且和玩家控制Pawn采用相同的接口。

玩家控制器(Player Controller) - 一种更特殊的控制器,用于从玩家的游戏手柄、触控板、鼠标/键盘获取输入信息,并使用这些信息驱动玩家所控制的Pawn或角色的行为。

那么一切都是Actor吗?

并非如此。Actor 是虚幻引擎中最常用于Gameplay的类,并且是唯一可以在 世界 中 生成 的类型。换句话说,你放入关卡中的一切内容都将是Actor。

另一个需要知道的重要类型是 Object 。Object实际上是所有虚幻的类的基类,包括 Actor 和其他许多类。它是比Actor级别低得多的类,但作为虚幻中的类,它仍拥有一些基本功能,例如 反射 和 序列化 。Object是一个非常基础的类,如果你需要定义一个新类型但又并非 Actor 时,就会使用它。例如,Actor组件 是所有组件的基类,派生自 Object 而不是 Actor 。

虚幻引擎中的Gameplay框架是什么?

当你开始新的Unity项目时,你必须手动填充GameObject和组件等事项。虚幻引擎也一样,你可以使用Actor和组件构建游戏。但是,虚幻引擎有一个额外的层,称为Gameplay框架。如果你使用特定图元类并遵循特定规范,你的游戏将自动获得原本实现起来困难又费时的额外功能(例如,完全多玩家支持)。

要使用Gameplay框架,你需要了解如何使用和自定义虚幻引擎随附的内置Actor类,例如 Pawn、角色(Character) 和 玩家控制器(Player Controller) 。例如,如果你想实现多玩家,你还需要熟悉虚幻引擎中网络和复制的工作方式。

在虚幻引擎中编写代码 写给C++程序员

假如是编写蓝图,你只需要用到虚幻引擎。你所需的所有功能已包括在内。

假如要编写C++代码,你还要在Windows上下载Visual Studio,或在macOS上安装Xcode。当你首次在虚幻引擎中创建新的C++项目(或将C++代码添加到现有项目)时,虚幻引擎将自动创建Visual Studio项目文件。

从虚幻引擎项目访问Visual Studio的方法有以下两种:

在 内容浏览器(Content Browser) 中,双击 C++类在Visual Studio中打开。

从主菜单,转至 工具(Tools)> 打开Visual Studio(Open Visual Studio) 。仅当你的项目包含至少一个C++类时,才会显示此选项。

虚幻引擎有一点很不同:有时必须手动刷新Visual Studio项目文件(例如,下载新版虚幻引擎后,或手动更改磁盘上的源文件位置时)。要这样做,可以采用以下两种方法:

从虚幻引擎的主菜单,转至 工具(Tools)> 刷新Visual Studio项目(Refresh Visual Studio Project) 。

Right-click the .uproject file in your project's directory and select Generate Visual Studio project files.

编写事件函数(Start、Update等)

如果你用过MonoBehavior,那你应该熟悉 Start 、 Update 和 OnDestroy 等方法。下面比较了Unity的行为与对应的虚幻引擎Actor和组件的行为。

在Unity中,某个基本组件的代码可能是这样:

public class MyComponent : MonoBehaviour { void Start() {} void OnDestroy() {} void Update() {} } 在虚幻引擎中,你可以在Actor本身上编写代码,而不是仅仅对新组件类型编码。这实际上十分常见且有用。 虚幻引擎Actor有一组类似于Unity的 `Start` 、 `OnDestroy` 和 `Update` 函数的方法。如下所示:

C++

UCLASS() class AMyActor : public AActor { GENERATED_BODY() // 游戏开始时调用。 void BeginPlay(); // 销毁时调用。 void EndPlay(const EEndPlayReason::Type EndPlayReason); // 每帧调用以更新此Actor。 void Tick(float DeltaSeconds); };

蓝图

image_29.png

虚幻引擎中的组件包含不同的函数。下面是一个基本示例:

C++

UCLASS() class UMyComponent : public UActorComponent { GENERATED_BODY() // 在创建所属Actor之后调用 void InitializeComponent(); // 在销毁组件或所属Actor时调用 void UninitializeComponent(); // 组件版的Tick函数 void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction); };

蓝图

image_30.png

记住,在虚幻引擎中,你必须调用方法的父类版本。

例如,在Unity C#中,可能是调用 base.Update(),但在虚幻引擎C++中,你将使用 Super::TickComponent():

void UMyComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { // 此处添加自定义更新内容 Super::TickComponent(DeltaTime, TickType, ThisTickFunction); }

在C++中,一些类使用以 A 开头,而另一些类以 U 开头。A 表示Actor子类,而 U 表示 Object 子类。另一个常用前缀是 F ,它用于大部分普通数据结构和非UObject类。

在虚幻引擎中编写游戏逻辑代码

下一小节介绍一些高级虚幻引擎编程概念。下面的说明假定你熟悉Unity C#并想学习虚幻引擎C++。话虽如此,在大部分情况下,你还可以使用蓝图并获得相同结果,因此我们尽可能同时添加了C++和蓝图的示例。

现在来看一些最常见的游戏逻辑编程模式,以及如何在虚幻引擎中实现它们。下面的示例介绍了一些常见Unity函数,以及如何在虚幻引擎中实现相同功能。

实例化GameObject/生成Actor

在Unity中,你会使用 Instantiate 函数创建对象的新实例。此函数可以获取任意 UnityEngine.Object 类型(GameObject、MonoBehaviour等),并创建其副本。

public GameObject EnemyPrefab; public Vector3 SpawnPosition; public Quaternion SpawnRotation; void Start() { GameObject NewGO = (GameObject)Instantiate(EnemyPrefab, SpawnPosition, SpawnRotation); NewGO.name = "MyNewGameObject"; }

虚幻引擎有两个不同的函数来实例化对象:

NewObject 用于创建新的 UObject 类型。

SpawnActor 用于生成 AActor 类型。

UObject和NewObject

在虚幻引擎中创建 UObject 的子类与在Unity中创建 ScriptableObject 的子类非常类似。对于不需要生成到世界中或像Actor那样绑定了组件的Gameplay类,这些很有用。

在Unity中,如果你创建自己的 ScriptableObject 子类,你会如下所示将其实例化:

MyScriptableObject NewSO = ScriptableObject.CreateInstance();

在虚幻引擎中,如果你创建自己的 UObject 派生类型,你可以如下所示将其实例化:

UMyObject* NewObj = NewObject(); AActor和SpawnActor

Actor使用World(C++中的 UWorld)对象上的 SpawnActor 方法生成。一些UObject提供了 GetWorld 方法(例如,所有Actor都如此)。你会采用此方法获取World对象。

请注意,在下面的示例中,我们传入了我们想生成的Actor的类,而不是传入另一个Actor。在我们的示例中,该类可以是AMyEnemy的任意子类。

要是你想创建另一个对象的副本,就像在Unity的Instantiate函数那样,你该怎么做呢?

NewObject 和 SpawnActor 函数也能给一个"模板"对象来工作。虚幻引擎将创建该对象的副本,而不是从头创建新对象。这将复制其所有UPROPERTY和组件。

AMyActor* CreateCloneOfMyActor(AMyActor* ExistingActor, FVector SpawnLocation, FRotator SpawnRotation) { UWorld* World = ExistingActor->GetWorld(); FActorSpawnParameters SpawnParams; SpawnParams.Template = ExistingActor; World->SpawnActor(ExistingActor->GetClass(), SpawnLocation, SpawnRotation, SpawnParams); }

你可能会好奇这里的"从头开始"到底是什么意思。你创建的每个对象类都有一个默认模板,其中包含其属性和组件的默认值。如果你不覆盖这些属性,也没有提供你自己的模板,虚幻引擎将使用这些默认值来构造你的对象。为了更好地说明这一点,我们首先来看一下MonoBehaviour示例:

public class MyComponent : MonoBehaviour { public int MyIntProp = 42; public SphereCollider MyCollisionComp = null; void Start() { // 如果尚无碰撞组件,则进行创建 if (MyCollisionComp == null) { MyCollisionComp = gameObject.AddComponent(); MyCollisionComp.center = Vector3.zero; MyCollisionComp.radius = 20.0f; } } }

在上面的示例中,我们有一个默认为42的 int 属性,以及默认为半径20的 SphereCollider 组件。

我们可以在虚幻引擎中使用对象的构造函数实现相同的效果:

UCLASS() class AMyActor : public AActor { GENERATED_BODY() UPROPERTY() int32 MyIntProp; UPROPERTY() USphereComponent* MyCollisionComp; AMyActor() { MyIntProp = 42; MyCollisionComp = CreateDefaultSubobject(FName(TEXT("CollisionComponent")); MyCollisionComp->RelativeLocation = FVector::ZeroVector; MyCollisionComp->SphereRadius = 20.0f; } };

在构造函数 AMyActor 中,我们为这个类设置了属性的默认值。请注意 CreateDefaultSubobject 函数的用法,我们可以使用此函数创建组件并向其分配默认属性。使用此函数创建的所有子对象都充当默认模板,因此我们可以在子类或蓝图中修改它们。

类型转换

在此例中,我们获取了一个已知的组件,将其转换为特定类型,然后判断能否执行一些操作。

Unity C#

Collider collider = gameObject.GetComponent; SphereCollider sphereCollider = collider as SphereCollider; if (sphereCollider != null) { // ... }

虚幻引擎C++

UPrimitiveComponent* Primitive = MyActor->GetComponentByClass(UPrimitiveComponent::StaticClass()); USphereComponent* SphereCollider = Cast(Primitive); if (SphereCollider != nullptr) { // ... } 销毁GameObject/Actor

Unity

Destroy(MyGameObject);

C++

MyActor->Destroy();

蓝图

image_23.png

销毁GameObject/Actor(延迟1秒)

Unity

Destroy(MyGameObject, 1);

C++

MyActor->SetLifeSpan(1);

蓝图

image_24.png ]

禁用GameObject/Actor

Unity

MyGameObject.SetActive(false);

C++

// 隐藏可见组件 MyActor->SetActorHiddenInGame(true); // 禁用碰撞组件 MyActor->SetActorEnableCollision(false); // 禁止Actor更新 MyActor->SetActorTickEnabled(false);

蓝图

image_25.png ]

从组件访问GameObject/Actor

Unity

GameObject ParentGO = MyComponent.gameObject;

C++

AActor* ParentActor = MyComponent->GetOwner();

蓝图

image_32.png ]

从GameObject/Actor访问组件

Unity C#

MyComponent MyComp = gameObject.GetComponent();

虚幻引擎C++

UMyComponent* MyComp = MyActor->FindComponentByClass();

蓝图

image_33.png ] 点击查看大图。

查找GameObject/Actor

Unity C#

// 按名称查找GameObject

GameObject MyGO = GameObject.Find("MyNamedGameObject"); // 按类型查找Object MyComponent[] Components = Object.FindObjectsOfType(typeof(MyComponent)) as MyComponent[]; foreach (MyComponent Component in Components) { // ... } // 按标签查找GameObject GameObject[] GameObjects = GameObject.FindGameObjectsWithTag("MyTag"); foreach (GameObject GO in GameObjects) { // ... }

虚幻引擎C++

// 按名称查找Actor(也适用于UObject) AActor* MyActor = FindObject(nullptr, TEXT("MyNamedActor")); // 按类型查找Actor(需要UWorld对象) for (TActorIterator It(GetWorld()); It; ++It) { AMyActor* MyActor = *It; // ... }

蓝图

image alt text

虚幻引擎C++

// 按类型查找UObject for (TObjectIterator It; It; ++it) { UMyObject* MyObject = *It; // ... } // 按标签查找Actor(也适用于ActorComponent,需要改用TObjectIterator) for (TActorIterator It(GetWorld()); It; ++It) { AActor* Actor = *It; if (Actor->ActorHasTag(FName(TEXT("Mytag")))) { // ... } }

蓝图

image alt text

向GameObject/Actor添加标签

Unity C#

MyGameObject.tag = "MyTag";

虚幻引擎C++

// Actor可以有多个标签 MyActor.Tags.AddUnique(TEXT("MyTag"));

蓝图

image alt text

向MonoBehaviour/ActorComponent添加标签

Unity C#

// 这会更改它绑定到的GameObject上的标签 MyComponent.tag = "MyTag";

虚幻引擎C++

// 组件有自己的标签数组 MyComponent.ComponentTags.AddUnique(TEXT("MyTag")); 比较GameObject/Actor和MonoBehaviour/ActorComponent上的标签

Unity C#

if (MyGameObject.CompareTag("MyTag")) { // ... } // 检查它绑定到的GameObject上的标签 if (MyComponent.CompareTag("MyTag")) { // ... }

虚幻引擎C++

// 检查某个Actor是否有此标签 if (MyActor->ActorHasTag(FName(TEXT("MyTag")))) { // ... }

蓝图

image alt text

虚幻引擎C++

// 检查某个ActorComponent是否有此标签 if (MyComponent->ComponentHasTag(FName(TEXT("MyTag")))) { // ... }

蓝图

image alt text

物理:刚体与图元组件

在Unity中,假如要为GameObject赋予物理特征,首先必须为其提供刚体组件。

在虚幻引擎中,任何图元组件(C++中的 UPrimitiveComponent)都可以是物理对象。一些常见图元组件如下:

形状组件(胶囊体、球体和盒体)

静态网格体组件

骨骼网格体组件

Unity将碰撞和可视性划分到不同的组件中,虚幻引擎则将"潜在的物理碰撞"和"潜在的可视效果"组合到了单个图元组件中。凡是在世界中具有形状的组件,只要能通过物理方式渲染或交互,都是 PrimitiveComponent 的子类。

层与通道

虚幻引擎中的碰撞通道对应Unity中的层。如需详细信息,请参阅碰撞过滤。

RayCast与RayTrace

Unity C#

GameObject FindGOCameraIsLookingAt() { Vector3 Start = Camera.main.transform.position; Vector3 Direction = Camera.main.transform.forward; float Distance = 100.0f; int LayerBitMask = 1 GetCameraLocation(); FVector End = Start + (PlayerCameraManager->GetCameraRotation().Vector() * 1000.0f); bool bHit = GetWorld()->LineTraceSingle(Hit, Start, End, ECC_Pawn, Params); if (bHit) { // Hit.Actor包含指向追踪所击中的Actor的弱指针 return Cast(Hit.Actor.Get()); } return nullptr; }

蓝图

image alt text

点击查看大图。

触发器体积

Unity C#

public class MyComponent : MonoBehaviour { void Start() { collider.isTrigger = true; } void OnTriggerEnter(Collider Other) { // ... } void OnTriggerExit(Collider Other) { // ... } } 虚幻引擎C++ UCLASS() class AMyActor : public AActor { GENERATED_BODY() // 我的触发器组件 UPROPERTY() UPrimitiveComponent* Trigger; AMyActor() { Trigger = CreateDefaultSubobject(TEXT("TriggerCollider")); // 两个碰撞物都需要将此项设置为true,才能触发事件 Trigger.bGenerateOverlapEvents = true; // 设置碰撞物的碰撞模式 // 此模式仅为光线投射、扫描和重叠启用碰撞物 Trigger.SetCollisionEnabled(ECollisionEnabled::QueryOnly); } virtual void NotifyActorBeginOverlap(AActor* Other) override; virtual void NotifyActorEndOverlap(AActor* Other) override; }; 虚幻引擎蓝图

image alt text

如需详细了解如何设置碰撞响应,请参阅碰撞页面。

刚体运动

Unity C#

public class MyComponent : MonoBehaviour { void Start() { rigidbody.isKinematic = true; rigidbody.velocity = transform.forward * 10.0f; } }

在虚幻引擎4中,碰撞组件和刚体组件是同一个组件。其基类是 UPrimitiveComponent,它有许多子类(USphereComponent、UCapsuleComponent 等)可满足你的需要。

虚幻引擎C++

UCLASS() class AMyActor : public AActor { GENERATED_BODY() UPROPERTY() UPrimitiveComponent* PhysicalComp; AMyActor() { PhysicalComp = CreateDefaultSubobject(TEXT("CollisionAndPhysics")); PhysicalComp->SetSimulatePhysics(false); PhysicalComp->SetPhysicsLinearVelocity(GetActorRotation().Vector() * 100.0f); } }; 输入事件

Unity C#

public class MyPlayerController : MonoBehaviour { void Update() { if (Input.GetButtonDown("Fire")) { // ... } float Horiz = Input.GetAxis("Horizontal"); float Vert = Input.GetAxis("Vertical"); // ... } }

虚幻引擎C++:

UCLASS() class AMyPlayerController : public APlayerController { GENERATED_BODY() void SetupInputComponent() { Super::SetupInputComponent(); InputComponent->BindAction("Fire", IE_Pressed, this, &AMyPlayerController::HandleFireInputEvent); InputComponent->BindAxis("Horizontal", this, &AMyPlayerController::HandleHorizontalAxisInputEvent); InputComponent->BindAxis("Vertical", this, &AMyPlayerController::HandleVerticalAxisInputEvent); } void HandleFireInputEvent(); void HandleHorizontalAxisInputEvent(float Value); void HandleVerticalAxisInputEvent(float Value); };

蓝图

image alt text

你的项目设置中的输入属性可能如下所示:

虚幻引擎中的输入设置

如需详细了解如何设置虚幻引擎项目的输入,请参阅输入页面。

常见问题解答 如何自动加载最后一个项目?

你可以将虚幻引擎配置为在启动时自动加载你之前处理的最后一个项目。从Epic启动程序打开项目时,在虚幻引擎启动屏幕上启用 在启动时总是加载最后一个项目(Always Load Last Project on Startup) 选项。

always-load-last-project-at-startup.png

哪里可以设置游戏的输入绑定?

在Unity中,你使用项目的输入管理器设置来设置默认绑定。

在虚幻引擎中,你从 项目设置(Project Settings) 窗口中的 输入(Input) 类别配置输入绑定。在此窗口中,你可以添加各种按钮(操作)和模拟功能按钮(轴)。为每个功能按钮提供名称和默认绑定。这样做之后,你就可以在触发输入事件时获得对游戏的Pawn的回调。

如需详细了解如何设置虚幻引擎项目的输入,请参阅输入页面。

如何更改项目的初始场景?

默认情况下,虚幻引擎会在你打开项目时加载默认关卡。你可以在 项目设置(Project Settings) 窗口(主菜单:编辑(Edit)> 项目设置(Project Settings))中的 通用(General)> 加载和保存(Loading & Saving) 类别中更改此行为。

如何运行游戏?

有多种方式可试玩(运行)你的游戏:

直接在虚幻编辑器中运行,方法是点击 主工具栏(Main Toolbar) 上的 运行(Play) 按钮。

作为独立的程序运行,方法是点击 主工具栏(Main Toolbar) 上的 平台(Platforms) 按钮,然后从下拉列表中选择你的机器。请注意,这会首先为你的平台编译一个可执行文件;例如,如果你在Windows机器上工作,这将构建Windows可执行文件。

在不同的平台(例如,移动设备或Web浏览器)上运行,方法是点击 主工具栏(Main Toolbar) 上的 平台(Platforms) 按钮,然后选择你想运行游戏的平台。请注意,你需要首先安装所有必需的软件。

如需详细了解如何在不同的平台上运行虚幻引擎游戏,请参阅以下页面:

运行和模拟

在虚幻编辑器中管理平台

虚幻引擎使用什么测量单位?

在Unity中,主要的测量单位是一米。在虚幻引擎中,主要测量单位是一厘米。

因此,在Unity中移动一个单位(米)相当于在虚幻引擎中移动100个单位(厘米)。

如果你想在Unity中移动2英尺,那就是0.61个单位(米)。在虚幻引擎中,这相当于61个单位(厘米)。

在虚幻引擎的坐标系中,哪个方向朝上?

Unity和虚幻引擎都使用左手坐标系,但坐标轴的命名方式不同。在虚幻引擎中,X的正方向是"前",Y的正方向是"右",Z的正方向是"上"。

如何查看游戏的输出日志?

点击 底部工具栏 中的 输出日志(Output Log) 按钮。

如何抛出异常?

不同于Unity,虚幻引擎并不处理异常。请改用 check() 函数来触发严重的断言错误。你可以传入错误信息提示。如果你想报告错误,但不希望打断程序,请改用 ensure()。这将记录一个带有完整调用堆栈的错误信息,但程序会继续执行。如果你附加了调试器,那么这两个函数都会暂定并进入调试器。

.NET Framework在哪里?

不同于Unity,虚幻引擎并不使用.NET Framework。虚幻引擎有自己的一套容器类和库。下面列出了常见的容器比较:

.Net Framework

虚幻引擎

String

FString,FText

List

TArray

Dictionary

TMap

HashSet

TSet

你可以在此处详细了解虚幻引擎的其他容器。

代码更改时虚幻引擎是否会自动重新加载?

会!你在编写代码时,可以将编辑器保持开启的状态。完成代码编辑后,从Visual Studio启动编译,编辑器将自动"热重新加载"你的更改。

查找帮助和答案

感谢阅读!本指南最初是在各地的虚幻引擎开发人员帮助下为虚幻社区而创建,现在我们已经针对虚幻引擎5进行了更新。随着我们不断了解如何更好地帮助大家过渡到虚幻引擎,我们会持续改新本文档,因此我们期待你的反馈意见和纠错意见。

要详细了解虚幻引擎,你可以参考本文档网站的其余部分,或访问下面的资源:

YouTube上的虚幻引擎

论坛

社区资源



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有