Ilingis 发表于 2022-8-1 15:42

(4)在UE场景中新建对象

在本节中,我们将建立一个自己的Actor对象,并且在场景启动时将它自动添加到场景中显示。这一步可以直接从编辑器中点击左下角的内容侧滑菜单,然后选中C++类/class04,在文件夹内容中右键点击并选择“新建C++类”来完成。我们选择建立一个新的Actor派生类,并且直接沿用默认设置,生成名为MyActor的新的场景对象类,并在VS IDE中自动生成对应的.h和.cpp文件。




新建立的类名为AMyActor,前缀A表示它是Unreal场景中的可放置对象。事实上这也是Unreal中最常见的一种物体类型。这个新建类已经自动声明和实现了两个重要的函数,即BeginPlay()和Tick()。
这里的BeginPlay()会在编辑器或者运行时程序启动关卡时被自动执行,而Tick()则会在场景渲染的主循环中被反复执行。这一点比较类似于Unity中新建一个MonoBehaviour时的策略,Unity会自动产生两个方法Start()和Update(),其作用与这里的两个方法基本相同。注意,Unreal需要在构造函数中声明:
PrimaryActorTick.bCanEverTick = true;
这样才会每帧自动调用Tick()函数,如果设置为false则不会调用该函数,这样可以避免一些无谓的运行时损耗。


现在我们有了一个全新的AMyActor类,它可以用来产生自定义的物体,然后可以放置到Unreal的场景当中显示。我们不想在第一步就把事情搞得太过复杂,所以只需要建立一个静态网格模型(Static Mesh),然后通过Tick()函数让它能够自动旋转就可以了。那么我们首先在AMyActor类中添加一个新的成员变量:
UPROPERTY(VisibleAnywhere)
UStaticMeshComponent* _mesh;
这里的UPROPERTY和之前提到的UCLASS有点类似,作用都是声明一些额外的特性,以便UnrealEditor中根据这些特性的不同对数据进行不同的显示或者编辑处理。VisibleAnywhere的意思,简而言之就是确保这个成员变量可以在编辑器中被看到,但是不能被直接修改。更多的属性特性定义可以参看:
https://docs.unrealengine.com/5.0/en-US/unreal-engine-uproperties/
在AMyActor的构造函数中,我们需要新建一个UStaticMeshComponent对象,并将它绑定到这个Actor对象之上。这一点也有点类似于Unity中的GameObject-Component机制,即,每个场景中的对象(Actor或者GameObject)都可以绑定一个或者多个功能组件(Component),用于承载不同类型的功能实现。对于Unreal的一个Actor对象而言,它至少应该有一个可用的功能组件,这个功能组件被称作RootComponent,可以直接在类的成员函数中访问到。
现在我们需要建立一个普通的立方体,对于Unreal而言,最简单的方式就是从已有的Starter Kit资源包中找到这个立方体模型资源,加载它到系统内存中,然后作为具体的网格模型数据设置给新建的UStaticMeshComponent。整个流程代码如下所示:


有可能有人会问这样一个问题:"/Game/StarterContent/Shapes/Shape_Cube.Shape_Cube"这个资源路径,应该如何获取到?事实上,我们只需要在内容侧滑菜单中,选中“内容/StarterContent/Shapes”,然后在里面找到我们想要使用的立方体模型素材,右键选择“复制引用”,就可以得到这样一段字符串:
StaticMesh'/Game/StarterContent/Shapes/Shape_Cube.Shape_Cube'
直接将它复制到FObjectFinder的参数中使用即可。由此我们即可从当前工程的资源库中得到一个模型,然后将它设置给静态模型的功能组件,并将这个组件绑定到我们的Myactor对象上。


我们现在可以编译工程,然后执行调试并打开UnrealEditor,此时如果我们直接运行当前关卡的话,是看不到任何变化的。但是如果我们再次找到内容侧滑菜单,然后选中C++类/class04的话,就可以直接把新生成的MyActor对象拖动到场景里,它会显示为一个立方体模型,并且可以拖动、旋转和随意放置。它现在和预设场景里的桌子和椅子已经毫无区别了。


不过毫无区别并不是本文的目标,我们在Tick()函数中做一个非常简单的绕自身垂直轴旋转的效果。然后再度将MyActor从素材窗口拖动到场景中,并启动当前关卡,此时可以看到这个立方体在缓慢地按照我们的期望转动了:




现在我们已经了解到如何去新建一个Actor对象并且将它放置到场景中了,但是目前必须是我们自己在编辑器里将它拖动到场景中放置。那么,如何在关卡启动时或者运行中的某个时刻,自动将这个立方体添加到场景中的某个位置呢?
Unreal提供了一个重要的方法来实现自动添加对象,即UWorld::SpawnActor()方法,它是一个模板函数,并且需要至少有一个FActorSpawnParameters类型的输入参数,用来标识一些添加对象时的基本需求,例如设置对象名称等。除此之外还可以同时设置物体放置在场景中的位置和旋转姿态信息。
我们依然选择在Aclass04GameModeBase::StartPlay()中,将之前新建的MyActor对象的一个实例自动添加到场景里,并且设置它的初始位置和旋转角度。编译运行UnrealEditor并启动当前关卡,可以看到下面的结果:




此时一个旋转的立方体将自动呈现在场景中,并且我们可以从左侧的大纲列表中找到它的存在,注意这个对象的实际名称为NewActor01(可以打开日志输出窗口并看到我们通过UE_LOG打印的名称),但是在大纲中显示的是MyActor-1。我们可以通过SetActorLabel()来修改大纲视图下的显示名称。此外,从属性细节窗口中可以看到,MyActor对象的成员变量_mesh也被显示在组件列表中,而位置姿态变换窗口中,Z方向的旋转角度正在不断发生变化——这是我们之前在Tick()函数中努力工作的成果。
我们现在已经了解了:如何从素材库中选择一个想要显示的素材,将它设置给一个新的静态模型组件,然后将这个组件绑定到新建对象,最后通过编辑器中拖拽或者直接在C++程序中通过SpawnActor()函数来添加对象到场景中的方法。结合上一节提到的按名称查询对象以及删除对象的方法,实际上我们已经有一定的经验去管理Unreal的三维场景,并且按照自己的实际需要去找到物体,并控制物体的摆放和属性变更了。如果沿着这个思考路径继续深化,就需要进一步了解一个Unreal模型素材的组成结构,并尝试自己从零去构建一个新的StaticMesh出来。这听起来颇有挑战,不过也确实是我们在非游戏应用当中经常要面对的问题。那么从下一个小节开始,我们会尝试对Unreal中的静态网格模型对象做深入的分析,并且尝试自己去构建它。
页: [1]
查看完整版本: (4)在UE场景中新建对象