使用虚幻引擎中的C++导论(二)
第一,这篇是我翻译的虚幻4官网的新手编程教程,原文传送门,有的翻译不太好,但大体意思差不多,请支持我O(∩_∩)O谢谢。
第二,某些细节操作,这篇文章省略了,如果有不懂的,去看其他教程。
第三,没有C++编程经验,但有其他OOP语言经验的朋友。要先了解C++的基础。
深入研究
你依然和我在这里冒险。太好啦,下一个话题,围绕游戏类的继承关系进行介绍。在这个部分,我们将要看到很多基类,谈一谈他们之间的关系,在这里我们可以看到虚幻引擎如何使用继承和组合去建立自己的游戏特性。
游戏类:Objects, Actors, and Components(对象,物体,组件)
你可以从很多的游戏基类中派生出这4种主要的类,它们是UObject,AActor, UActorComponent,和 UStruct。他们的每一块都建立自下面的部分。当然了,你可以建立一个不继承任何类的类,但它们将不能用于引擎特性有关的部分。典型类(普遍意义上的C++类)的使用方法是,在UObject对象层次之外创建的:集成第三方库;操作系统的特定功能包装,等等。
虚幻对象(UObject)
在虚幻中最原始的基类叫UObject。这个类,加上UClass类,提供了若干虚幻引擎的主要基础服务:
- 属性与方法的反射
- 属性信息序列化
- 垃圾回收
- 通过名称查找虚幻对象
- 为属性配置值
- 属性和方法的网络支持
每个派生自UObject的类都有一个单独的UClass类被创建,它包含所有有关类实例的元数据。UObject和UClass是每一个虚幻对象的最高父类。理解他们之间的区别的最好办法是,UClass将描述UObject看起来是什么样子的,如什么属性是可以被序列化的,什么属性可以支持网络,等等。很多游戏开发不会直接继承UObjects类,但是作为替代,那些类继承AActor类和UActorComponent类。在写游戏代码时,你不需要知道UClass/UObject类是怎么工作的细节,但你最好知道这些类在这个系统中是存在的。
AActor
AActor类意味着它将是游戏体验的一部分。AActor类可以被设计师在关卡设计中放置,也可以通过运行时由系统放置。所有的对象都可以通过继承该类,让对象可以放置在关卡中。比如说,AStaticMeshActor类,ACameraActor类,APointLight类。AActor类继承UObject类,这样就得到了前一节(翻译的上一篇文章)的所有特性。AActor可以明确的被销毁,可以通过C++代码或蓝图操作,或在某个拥有的关卡(场景)不再被装载时,通过标准垃圾回收机制销毁。AActors 负责游戏对象的高级行为。AActors 同样是可以再网络中复制的,在网络复制时,AActors 可以同时分发信息到支持网络的UActorComponents (组件)中。
AActors 有他们自己的行为(通过特殊继承),但他们也像UActorComponents 层次关系的箱子一样(通过特殊组合),这是通过AActors 的RootComponent (根组件)成员完成的,它包含了一个单独的UActorComponent ,反过来说,可以包含很多其他组件。在把AActor 放置到关卡之前,AActor 必须包含最少一个USceneComponent类的组件,USceneComponent类可以对AActor 进行平移,旋转,缩放。
(通俗解释:一定要让整个物体至少有个形状的组件,才能放到场景中)
AActors 有几个事件会在AActors 的生命周期中被调用(触发)。下面的列表简单列出了一些事件说明。
- BeginPlay - 当物体第一次进入场景时触发。
- Tick - 每一帧调用一次。
- EndPlay - 在物体离开游戏空间时触发。
查看更多关于AActor类的详细说明,传送门
运行时生命周期
现在将要介绍的是,我们刚才提到的生命周期,对于被放置进关卡中的AActor来说,要理解生命周期,可以简单的想象一下:物体被放进关卡,然后关卡在某个时候被关掉了,最后物体被销毁了。那么在运行时的生成和销毁的过程是什么样的呢?在运行Spawning(产卵)时,虚幻引擎会调用生成方法。Spawning是一个Actor比新建一个普通对象稍微复杂一点的“生成”。因为,为了满足Actor的所有功能需求,Actor需要在多种运行的系统进行注册。初始位置和旋转需要进行设置。物理系统需要知道Actor的存在。时钟计时需要知道物体的存在。还有很多其他系统。因此,我们有一个方法为Actor提供Spawning。UWorld::SpawnActor(),每当一个物体成功的Spawning之后,BeginPlay()方法将被调用,紧接着Tick()方法将在下一帧被调用。
当Actor生命周期结束时,你可以调用Destroy()方法。在这个过程中,EndPlay()方法将被调用,在这里你可以自定义一些逻辑。另一些控制Actor生命周期长短的选项,是使用Lifespan 成员。你可以在Actor构造或其他代码运行时,设置timespan(时间跨度)。一旦该时间过期,Actor将自动调用Destroy()方法。
想要学习更多关于 产卵 Actor ,请看生成Actor页,传送门
UActorComponent
UActorComponent有他们自己的行为,他们通常负责功能化,这些组件通常被AActor共享。比如,提供可视化网格,粒子系统,摄像机视角,物理交互。当AActor在游戏中是一个与游戏整体角色有关联的高级目标,UActorComponent通常去表现个别的任务,去支持更高级别的对象。组件同样可以连接到别的组件,或者可以作为Actor的根组件。一个组件只能连接到一个父组件或父Actor,但可以有很多子组件连接到他自己。这些组件组成了组件树。子组件的位移,旋转,缩放是相对于父组件或父Actor的。
这里有很多途径去使用Actor或组件,有一种对于Actor与组件关系的思考是这样的,Actor表示“ 这个是什么东西”,组件表示“这个东西是由什么组成的”。
- RootComponent - 树型组件组织关系中的根部
- Ticking - 组件的时钟,是Actor时钟的一部分
剖析第一人称角色
在我们上一个小结,我们说了好多解释性的信息,但没有太多演示。为了更好的说明Actor与组件之间的关系,让我们深入挖掘一个蓝图类,这个类在你新建第一人称模板项目时就已经生成了。下面的图片中展示了FirstPersonCharacter Actor的组件树。根节点是一个CapsuleComponent(胶囊组件),连接着“胶囊组件”的是,一个ArrowComponent(箭头),Mesh (网格),FirstPersonCameraComponent(摄像机)。最下面的子叶节点是Mesh1P 组件,意味着第一人称网格关联到第一人称摄像机。
事实上,这个组件树的效果如下图所示,你可以看到所有的组件在3D空间中如我们期望的一样。
在这个例子中,组件树中的组件都连接于一个Actor。你可以通过使用继承和组合,去创建复杂的对象。当你想要自定义已有的AActor或UActorComponent时,需要用继承。在很多不同的 AActor类型*享功能时,需要用组合。
UStruct
使用UStruct,你无须继承特定的类,你只需要在结构体上标记USTRUCT()宏命令,引擎会帮你做其他基础工作。不像UObject那样,UStructs 不能被垃圾回收。如果你生成了他们的动态实例,你必须自己管理他们的生命周期。UStruct是一种朴素而古老的数据类型,它有UObject 的反射机制支持,但是没有虚幻引擎编辑器,蓝图操作,序列化,网络,等等,这些支持。
直到现在,我们谈了谈类的构造和基础继承。是时候再一次选择你的路了。你可以去阅读我们的游戏类,传送门。通过看实例去了解更多信息。或者为了制作游戏挖掘更深的C++特性。