ue4和unity对比

ON THIS PAGE

本指南将从Unity用户的视角来介绍虚幻4,并帮助你将Unity的开发经验应用到虚幻4的世界中。

编辑器

下面分别是Unity编辑器和虚幻编辑器的截图,我们用颜色标出了界面中的不同区域,并用相同颜色标出了拥有相同功能的区域。每个区域上还添加了名称,以便你了解它们在虚幻引擎语境中的称呼。虚幻编辑器支持自定义布局,你可以通过拖动各个窗口来移动它们。

编辑资产

Unity中,用户使用Inspector选项卡来编辑当前选中的资产。在虚幻4中,我们使用 细节 面板来展示当前选中对象的属性,比较复杂的编辑工作则有专门的窗口或选项卡来处理。每编辑一项资产,都会单独打开一个带有选项卡的窗口,类似于网页浏览器。当然这窗口也可以任意拖拽,或者悬浮在其他窗口之上作为独立窗口显示。

术语简表

下表左侧是Unity中的常见术语,右侧则是对应的(或差不多的)虚幻4术语。虚幻4的关键词直接链接到更进一步的虚幻在线文档中。

 

项目文件和文件

怎么理解项目中的目录和文件?

Unity项目一样,虚幻项目也保存在专门的目录结构中,并且有着自己的项目文件。你可以 双击 .uproject 文件打开虚幻编辑器并加载该项目,或者 点击右键 查看更多选项。项目目录包含不同子目录,保存了游戏的资产内容和源代码,以及各种配置文件和二进制文件。其中最重要的就是 Content 子目录和 Source 子目录。

我的资产应该放在哪里?

在虚幻4中,每个项目都有一个 Content 文件夹。它类似于Unity项目的Asset目录,是你保存游戏资产的地方。假如你要在游戏中导入资产,只需要将资产拷贝到Content目录,它们便会自动导入并出现在 内容浏览器 中。当使用外部程序修改这些资产时,编辑器中的资产也会自动更新。

支持哪些常见文件格式?

Unity支持很多文件格式。虚幻4也支持最常见的文件格式,如下表:

场景是如何保存的?

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

如何修改项目设置?

所有项目设置都可以在主菜单的 编辑(Edit / 项目设置(Project Settings 中找到。和Unity的设置类似,它们允许你设置项目信息(比如项目名称和图标),配置游戏输入绑定,定义运行项目时引擎的行为。你可以在这里 了解更多关于项目设置的单独信息。Unity还有叫做"玩家设置"的部分,在虚幻中,我们叫"平台设置",你可以在项目设置的"平台"分类里找到该设置。

源文件在哪里?

Unity中,用户习惯将C#的源文件放在资产目录中。

虚幻4的工作机制有点不同。假如项目包含C++代码,你会在项目目录中找到一个 Source 子目录,其中包含各种文件,包括C++源文件(.cpp)和头文件(.h),以及一些编译用的脚本(.Build.cs.Target.cs)。不过,如果项目只包含蓝图,则项目中没有Source目录。

在虚幻4中使用C++的最简单做法就是通过编辑器菜单 为项目添加代码(Add Code To Project(在主菜单的文件菜单中),或者直接用某个模板新建一个C++项目。你可以在 内容浏览器 中直接找到C++类,双击它们能直接在Visual StudioXcode中打开该文件。

GameObjectsActors

GameObject去哪里了?

Unity中,GameObject是可以放置在地图中的"东西"。虚幻4中对应的概念是Actor。在虚幻编辑器中,你可以从放置面板直接拖一个空的Actor放置到场景中:

你虽然可以通过空Actor来制作游戏,但虚幻4提供了各类特殊Actor,并预制了它们的特性,比如Pawn(用于作为玩家或者AI的角色),或者Character(用于会做动作的生物)。和空Actor一样,你可以直接将它们拖拽至场景中,并给它们添加组件,或自定义属性。你之后会学习到更多相关内容,但目前你只需了解虚幻4采用(Gameplay框架)[(Gameplay/Framework)]来协同各种特殊的Actor一起工作。

虚幻4中的ActorUnity中的GameObjects稍有不同。在Unity中,GameObject属于C#类,并且无法直接扩展。在虚幻4中,Actor属于C++类,而且允许你通过继承来拓展和自定义。关于这点,我们以后会具体介绍!

组件在哪里?

Unity中,你可以通过为GameObject添加组件来赋予其特定的功能。

在虚幻4中,你也可以为Actor添加组件。在关卡中放置一个空Actor后,点击"添加组件"按钮(位于 细节 面板中),然后选择一个组件来添加。这里让我们创建一把火炬:首先放置一个空Actor,然后添加一个网格体组件作为基座,再添加一个光源和粒子系统作为它的火焰。

Unity中,GameObject以列表形式保存组件,但在虚幻4中,Actor 层级 形式保存它的组件,并且组件之间相互绑定。你可以在上面的例子中看到,光源和粒子与网格模型相互绑定。之后在 复合Actor 复合GameObject 中会对此进行讨论。

UnityPrefabs到虚幻4的蓝图类

Unity的工作流程是基于 预制件(prefab 的。在Unity中,你一般是创建一系列带有组件的GameObject,然后基于它们生成Prefab。然后你在场景中放置Prefab的实例,或者在运行时将它们实例化。

虚幻4则基于蓝图类来工作。在虚幻4中,你一般是创建一个带有组件的Actor,然后选中它并点击 蓝图/添加脚本(Blueprint / Add Script 按钮(位于 细节 面板中)。然后选择一个位置保存你的蓝图类,点击 创建蓝图(Create Blueprint 来保存你新建的蓝图!

新建的蓝图类可以在 内容浏览器 中找到。你可以直接 双击 打开编辑它们,也可以将它们拖拽到任意场景关卡中。

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

Unity中,你通过为GameObject添加脚本(Script)组件来添加C#脚本内容。你通过创建继承自MonoBehavior的类来定义脚本组件的功能。

虚幻4也有类似的内容。你可以自由创建全新的组件类,并将它应用于任意Actor。组件类可以使用蓝图脚本创建,也可以用C++创建。

那么在虚幻4中如何创建自己的组件类呢?在 细节 面板中,添加组件(Add Component)的下拉框中,可以看到,你可以新建组件,或者选择已经存在的组件:

Unity中,每当你新建一个继承自MonoBahaviour的类,你都会得到一个模板文件,其中包含Start()函数和Update()函数。

在虚幻4中,也有一个充当模板的类,其中包含InitializeComponent()函数和TickComponent()函数,它们和StartUpdate具有类似的行为。

如果你创建的是蓝图脚本组件,则会看到类似的函数由可视化节点的形式展现:

可编辑脚本的Actor蓝图类

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

除了支持蓝图可视化脚本,虚幻4还支持通过C++代码来实现功能。 这里对比了UnityUE4中的代码,还给出了对应的蓝图实现:

UE4蓝图

虚幻4蓝图类的扩展性

Unityprefab和虚幻4的蓝图类都可以在游戏中实例化。不过,Unityprefab在相互嵌套时会产生比较复杂的状况,从而限制其可扩展性。

在虚幻4中,你可以让新建的蓝图类继承某个现有的蓝图类,然后通过新的属性、组件和可视化脚本功能来增强它。

比如,在虚幻4中,你可以创建一个叫做Monster的蓝图类,用它实现基本的怪物功能,比如追击人类。然后你可以再创建一个蓝图类来扩展它,比如Dragon(会喷火的怪物),或者Grue(天黑后会吃人的怪物),以及其他8种类型。这些Monster子类都继承了Monster父类的功能,并在此基础上获得了新的能力。

Unity中,你需要创建很多不同的GameObject prefab才能实现这点:你要为Dragon创建一个prefab,为Grue创建一个prefab,诸如此类。假设你希望为所有怪物都添加某个功能,比如添加一个Speak组件来让它们说话,在Unity中你需要更新所有10prefab,把功能拷贝粘贴到每个prefab中。

在虚幻4中,你只需简单地修改Monster的蓝图类,为它新增Speak的能力,然后就OK了!DragonGrue以及其他8Monster的子类都会自动继承这个说话的新功能,并不需要你去一一修改。

好处还不止这些!我们关于蓝图类所说的一切,同样适用于C++类,也同样对Actor 组件 适用。这些系统从设计之初就能支持大规模开发可扩展功能,可以为10个开发人员的项目服务,也可以为100个人的项目服务。

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

蓝图可视化脚本适合实现简单的游戏逻辑以及按顺序进行的事件。这个系统对策划、美术以及面向可视化编程的程序员是非常好用的,它能以可视化的方式轻松访问并管理游戏内对象。你完全可以仅凭蓝图完成一个游戏的制作。请参考Tappy Chicken示例,它是一个完整的范例。

C++编程适合用于大型任务,比如编写某个游戏逻辑系统,制作复杂的AI行为,或者新增引擎功能。对于已经掌握了C++技能的开发人员来说,可以翻阅一下 在虚幻4中的C++编程简述 页面。

大部分的项目都适合混合使用蓝图和C++。很多开发者都用蓝图来创作游戏原型,因为这个过程容易而且有趣,但之后出于性能优化、项目优化等考量,会把它们迁移到C++中。

蓝图类也能扩展C++

虚幻4的游戏开发中很多令人着迷的过程来存在于程序员用C++实现新的功能,而策划和美术在蓝图中使用这些功能,并提出更多要求!下图是针对一个虚幻4的射击游戏项目中实现拾取物品过程时,团队的一种形式,混合了C++类的编程实现,以及蓝图类用于处理行为和表现。

变换(Transform)组件

Unity中,每个GameObject都有一个变换组件(Transform Component),用于指定该GameObject在世界中的位置、旋转度以及缩放比例。

虚幻4也一样,Actor有一个 Root Component,能够作为场景组件的任意子类。场景组件(Scene Component 指定了Actor在世界中的位置、角度及缩放比例,而这些属性会影响该Actor的所有子对象。很多有用的组件都是场景组件的子类,因此让它们具有位置信息是非常有用的!

即便你只放置一个空Actor,虚幻4也会为它创建一个"默认场景根(Default Scene Root"对象,这是一个最简单的场景组件。当你放置一个新的场景组件时,默认场景根对象会被替换掉。

复合对象

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

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

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

我是否应该用组件来创造其他一切?

其实这完全取决于你自己,大部分情况下,你应该是结合使用Actor类和一些自定义组件。我们先前已经提到过,虚幻4已经提供了一些特殊类型的Actor,它们附带一定功能,并且包含某些组件。比如一个 Character 总是会包含一个 Character Movement组件

引擎中你会很快遇到一些继承自Actor的子类,大部分游戏都会用到它们。这里列出了一些与Actor相关的最常见的类:

  • Pawn - Actor的一种类型,用于表现一个可供控制的游戏对象,比如玩家操控的角色。玩家或者AI通常通过Controller来控制并移动Pawn
  • Character -一种特殊类型的Pawn,用于双足类型的角色,并具备一些复杂的功能。
  • Controller -占有并控制一个Pawn。通过将PawnController的分离,我们可以编写AI Controller,用于控制Pawn,并且和玩家控制Pawn采用相同的接口。
  • Player Controller -一个更为特殊的Controller,用于从玩家的手柄、触控板、鼠标/键盘获得输入信息,并将这些信息驱动玩家所控制的Pawn或者Character的行为。

那么所有的东西都是Actor咯?

并非如此。Actor 是虚幻4中最常见的用于游戏的类,并是唯一能够在 世界  生成 的类。因此任何能放置在关卡中的对象都属于Actor

另外一个需要知道的关键类是 ObjectObject实际上是所有虚幻引擎的类的基类,包括Actor以及其他一些类都是如此。这是一个比Actor更加底层的类,但作为虚幻中的类,它仍拥有一些基本功能,比如 反射  序列化Object是一个非常基础的类,当我们需要定义一个新的类但又并非Actor的时候会使用它。比如Actor Component是所有组件的基类,而它则是继承Object而非Actor

虚幻4Gameplay框架是什么东西?

好吧,从这里开始事情就开始变得有趣了(酷炫的方向)。Unity提供了一个干净的框架用于设计游戏,虚幻也做了同样的事情。Unity中你可以基于GameObjects和组件来创建所有东西,而在虚幻中则是基于Actor和组件来创建。

不过,虚幻在顶层提供了叫做 Gameplay框架 的机制,而Unity完全没有这类内容。虽然做游戏并非一定要用这个框架,但如果用的话会非常酷!简单来说,假如你能利用一些基础类,并且遵循特定规范,你就能很容易获得一些很赞的功能,否则你自己实现可能要花费很多时间,而且也很困难,或者很难改造。(比如完整的多人游戏支持!)

已有大量的酷炫游戏在开发时采用了虚幻的Gameplay框架,所以它很值得你花点时间来了解。没错,你可以自己实现这类框架,这么做完全没问题!但虚幻4当前已有数以百计的炫酷开发者在使用它,因此我们花点时间来了解一下。

要使用Gameplay框架,你只需要了解一些预制的Actor类,比如 PawnCharacter,和 Player Controller,并逐步了解虚幻的网络复制和网络其他功能。现在我们先回到最基本的部分。

如何在虚幻4中编写代码

写给MonoDevelop的程序员

假如是编写蓝图,你只需要用到虚幻编辑器——所有工具都已包括在内!假如要编写C++代码,你还要在Windows平台下载Visual Studio的免费版本,如果是Mac的话则需要安装Xcode。当第一次创建一个新项目(或者为已有项目添加代码)时,虚幻4将会自动创建Visual Studio项目文件。你只需要在 内容浏览器 中双击一个C++的类便能在Visual Studio中打开它,或者在主菜单的文件菜单中点击 Open Visual Studio

虚幻4有一点很不同:有时必须手动更新Visual Studio项目文件(比如,下载了UE4的新版本,或者对源代码文件的磁盘存放位置做了人为改变)。你可以通过在主菜单中点击 Refresh Visual Studio Project 或者在项目目录中 右键点击 .uproject文件 并选择 Generate Visual Studio project files 便可。

编写事件函数(StartUpdate等)

如果你用过MonoBehaviors,那你一定熟悉StartUpdateOnDestroy这类方法。以下是对Unity的行为和对应的虚幻4Actor和组件的比较。

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

请记住,在虚幻4中,你可以直接为Actor写代码而无需创建新的组件来添加代码。这其实是很常见并有意义的。

类似于UnityStartOnDestroyUpdate函数,虚幻4Actor中有类似的方法:

C++

蓝图

在虚幻4中,组件使用不同的函数。以下是示例:

C++

蓝图

注意,在虚幻4中调用基类方法很重要。

比如,在Unity C#中可能是调用base.Update(),但在虚幻4C++中我们使用Super::TickComponent()

你也许已经注意到C++中有些类以"A"开头,而其他一些类以"U"开头。前缀"A"代表它是Actor的子类,而前缀"U"代表它是Object的子类。还有其他一些前缀,比如"F"通常表示一个简单的数据结构类,或者其他非Uboject类。

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

好了,现在开始稍微深入一些。我们将探讨游戏创建相关的关键编程话题。因为你了解Unity,我们将从C#用户的角度来解释C++的功能,当然你也可以使用蓝图来完成几乎所有的事情!我们会尽可能提供用C++和蓝图编写的范例。

先说一下一些通用的游戏逻辑编程模式,以及如何在虚幻中实现它们。许多Unity中的函数在虚幻中都有类似的函数。我们先从最常见的开始。

实例化GameObject /生成Actor

Unity中,我们使用Instantiate函数来新建对象的实例。

该函数可以获取任意一种UnityEngine.Object类型(GameObjectMonoBehaviour等),并创建它的拷贝。

在虚幻4中,根据不同的需要,你需要用一些不同的函数来实例化对象。NewObject用于新建UObject类型的实例,而SpawnActor用于新建AActor类型的实例。

首先我们简单说下UObjectNewObject。在虚幻中, 子类化UObject很像在Unity中子类化ScriptableObject。它们适用于实现一些不需要在游戏中生成的类,或者不需要像Actor那样添加组件的类。

Unity中,如果要创建自己的ScriptableObject子类,你可以这样实例化:

在虚幻中,如果要创建UObject的继承类,是像下面这样的初始化:

那么Actor呢?ActorWorldC++中的UWorld)对象中生成是通过SpawnActor方法。如何获取World对象?有些UObject会提供一个GetWorld的方法,所有的Actor都具有这个方法。

你会发现,相比传入另一个Actor,我们会传入要生成的Actor"class"。在我们的范例中,"class"可以是AMyEnemy类的任意子类。

但如果你想创建某个对象的"拷贝",就像UnityInstantiate函数那样,你该怎么做呢?

NewObjectSpawnActor函数也能通过给一个"模板"对象来工作。虚幻引擎会创建该对象的拷贝,而不是"从零创建一个新的对象"。这会拷贝该对象的所有属性(UPROPERTY)和组件。

你也许想知道"从零开始创建"在这里具体是什么意思。每个对象类在创建时都有一个默认模板,包含了它的默认属性和组件。在创建时如果你并不想修改这些默认属性,也没有提供你自己的模板,虚幻将使用这些默认值来创建该对象。为了更好的说明这个,我们先来看一下MonoBehaviour的例子:

在上面这个例子中,有一个int属性,默认是42,还有一个SphereCollider组件,默认半径是20

在虚幻4中,我们可以利用对象的构造函数达到同样的效果。

AMyActor的构造函数中,我们为这个类设置了属性的默认值。请注意CreateDefaultSubobject函数。我们可以用它来创建组件并赋予组件默认值。我们使用这个函数创建的所有子对象都作为默认模板,所以我们可以在子类或蓝图中修改它们。

类型转换

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

Unity C#:

虚幻4 C++:

通过GameObject / Actor访问组件

Unity

MyComponent MyComp = gameObject.GetComponent<MyComponent>();

C++

UMyComponent* MyComp = MyActor->FindComponentByClass<UMyComponent>();

蓝图

查找GameObjects / Actors

GameObjects / Actors添加标签

MonoBehaviours / ActorComponents添加标签

比较GameObjects / ActorsMonoBehaviours / ActorComponents的标签

物理:刚体vs.图元(Primitive)组件

Unity中,假如要给一个GameObject赋予物理特性,需要给它添加一个刚体组件。在虚幻中,任何图元组件(C++中为UPrimitiveComponent)都可以是物理对象。一些通用的图元组件,比如ShapeComponent(胶囊形,球形,盒形),StaticMeshComponent,以及SkeletalMeshComponent

Unity不同,Unity将碰撞和可视性划分到不同的组件中。而虚幻则将潜在的物理碰撞和潜在的可视效果组合到了PrimitiveComponent中。任何在世界中具有形状的物体,要么就是能够被渲染显示,要么就是能和继承自PrimitiveComponent的物理子类交互。

vs通道

Unity中,它们被称为"层(Layer"。虚幻则称之为碰撞通道(Collision Channel),它们是类似的概念。你可以在 此处 了解更多内容。

RayCast vs RayTrace

虚幻4 C++

虚幻4蓝图:

点击查看大图。

触发器

Unity C#

虚幻4 C++

虚幻4蓝图:

你还可以在 这里 进一步了解如何设置碰撞响应。

刚体运动(Kinematic Rigidbodies

Unity C#:

在虚幻4中,碰撞组件和刚体组件是同一个组件,它的基类是UPrimitiveComponent,这个基类有很多不同的子类(USphereComponentUCapsuleComponent等)来配合不同的需求。

虚幻4 C++

输入事件

Unity C#

虚幻4 C++

虚幻4蓝图:

这里是项目设置和输入属性有关的设置界面:

关于如何设置输入,你可以从在 这里 了解更多。

常见问题

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

如果你习惯了Unity的自动加载最后项目的功能,在虚幻4中也一样可以做到。要开启这个功能的话,请在当打开项目时勾选"启动时总是加载最后一个项目"。你可以随时通过编辑器主菜单中的 编辑/编辑器首选项/加载和保存/启动 来修改设置。

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

Unity中,如果你习惯于为项目用Input Manager来设置默认的输入的话,虚幻4也一样。你可以打开项目设置,并选择Input的分类。然后就可以添加不同的案件(Action)或者摇杆控制(Axe)。给每一种控制一个名称和默认绑定。然后,在游戏中的Pawn中当该输入事件发生时就能获取回调函数。查看 输入文档页面 来了解详情。

如何修改项目的默认初始场景?

你可以在项目设置选项卡中设置项目的默认初始场景。从主菜单中选择 编辑/项目设置->地图和模式 便能进行修改。

如何运行游戏?

运行游戏最简单的方式是点击编辑器的主工具栏上的"运行"按钮,这会在编辑器窗口中运行游戏。如果想要以单独程序运行游戏,点击"运行"按钮边上的下拉箭头,并选择"独立窗口运行(Standalone Game"。如果想要在移动设备或者网页浏览器中运行游戏,那需要使用工具栏中的"启动"按钮(对应平台需要预先安装所需软件)。

引擎使用什么测量单位?

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

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

如果想要在Unity中移动2英尺,那么相当于0.61个单位,而在虚幻4中则是61个单位。

坐标系是怎么回事?那个方向朝上?

Unity和虚幻4都使用左手坐标系,但坐标轴则需要轮换一下。在虚幻4中,X的正方向是""Y的正方向是""Z的正方向是""

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

在虚幻4编辑器中,你可以从"窗口->开发人员工具"的菜单中打开"输出日志"。也可以在运行游戏时增加"-log"命令行参数,在游戏窗口以外启动一个专用的日志窗口,这非常有用!

说道日志输出,Debug.log在哪里?

虚幻4中的日志是高度可定制化的。阅读 这里 了解如何记录信息。

如何抛出异常?

Unity中,你可能习惯了发生问题时抛出异常。虚幻4并不处理异常。取而代之的做法是,使用'check()'函数来触发严重的断言错误。你可以传入一个错误信息提示。如果只是想报告一个错误,但不希望打断整个程序,你可以使用'ensure()'。这会记录一个带有完整调用堆栈的错误信息,但程序会继续执行。如果当前附加了调试器,那么这两个函数都会暂定并进入调试器。

.NET Framework去哪里了?

Unity不同,虚幻4并不使用.NET Framework。虚幻4有自己的一套容器类和库。常见的容器来对照:

你可以在这里 进一步了解虚幻4的其他容器。

代码改变时虚幻会自动重新加载吗?

是的!你可以在编写代码时保持编辑器开启的状态。要在编写完成后直接从Visual Studio中编译代码,编辑器则会"热加载"你刚刚做的改动。你也可以点击编辑器主工具栏上的 编译 按钮。这招在你附加了Visual Studio调试器时也很有用。