Gameplay Classes
每个虚幻游戏类都是一个.h和一个.cpp组成。
类在虚幻中有便准的命名模式。
前缀:
A
继承于可量产的游戏性类。他们都是Actor,可以直接在游戏中生成。
U
继承于所有游戏性对象。不能在游戏中直接生成,必须属于一个Actor。一般都是 Components.
在编辑器中使用C++ Class Wizard添加一个类,这样可以自动的更新游戏模块。生成的文件将会自动包含类声明和构造函数定义以及UCLACC()宏(以便引擎知道这个类的存在)。
每个游戏类都有各自的头文件。命名就是类名减去前缀。Actor.h的头文件是AActor
头文件使用标准c++语法加上一些宏来简化类、函数、变量的定义。
每个游戏类的开头应该包含生成头文件:#include "ClassName.generated.h"
UCLASS([specifier, specifier, ...], [meta(key=value, key=value, ...)]) class ClassName : ParentName { GENERATED_UCLASS_BODY() }
GENERATED_UCLASS_BODY()宏必须放在类的开始。
类说明符:
说明符可以控制类与引擎以及编辑器的各方面的行为。
-
类构造函数:
UObjects
使用构造函数来设置属性默认值和其他的变量,以及其他必要的初始化。可以直接在头文件中定义构造函数,但是必须把UCLASS指定为CustomConstructor,以防止自动生成器在头文件中生成一个构造函数声明。
AMyClass::AMyClass(const FPostConstructInitializeProperties& PCIP) : Super(PCIP) { }
参数:FPostConstructInitializeProperties结构对象用来对未初始化的属性进行初始化,这些初始化值来自原型和CDO(class default object)。
对象属性的一次性构造:
ATimelineTestActor::ATimelineTestActor(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP) { // Structure to hold one-time initialization struct FConstructorStatics { ConstructorHelpers::FObjectFinder<UStaticMesh> Object0; FConstructorStatics() : Object0(TEXT("StaticMesh'/Game/UT3/Pickups/Pickups/Health_Large/Mesh/S_Pickups_Base_Health_Large.S_Pickups_Base_Health_Large'")) { } }; static FConstructorStatics ConstructorStatics; // Property initialization StaticMesh = ConstructorStatics.Object0.Object; }
struct FConstructorStatics是一个一次性构造机构体,在构造函数中声明,且被定义为静态。这意味着构造函数中处于结构体内部的初始化工作仅仅只会在第一次构造的时候进行一次,以后的对象创建仅仅使用此静态对象即可。
ConstructorHelpers是一个名字空间(其实是一个结构体)专门提供构造工具(这些工具也全部都是结构体或者结构体模板)。比如FObjectFinder<>。
注意这里面的静态结构体是一种通用技巧,并不是仅仅在虚幻中有效。
Asset引用:
ATimelineTestActor::ATimelineTestActor(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP) { // Structure to hold one-time initialization struct FConstructorStatics { ConstructorHelpers::FObjectFinder<UStaticMesh> Object0; FConstructorStatics() : Object0(TEXT("StaticMesh'/Game/UT3/Pickups/Pickups/Health_Large/Mesh/S_Pickups_Base_Health_Large.S_Pickups_Base_Health_Large'")) { } }; static FConstructorStatics ConstructorStatics; // Property initialization StaticMesh = ConstructorStatics.Object0.Object; }
类引用:
APylon::APylon(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP) { // Structure to hold one-time initialization struct FConstructorStatics { ConstructorHelpers::FClassFinder<UNavigationMeshBase> Class0; FConstructorStatics() : Class0(TEXT("class'Engine.NavigationMeshBase'")) { } }; static FConstructorStatics ConstructorStatics; NavMeshClass = ConstructorStatics.Class0.Class; }
指向一个UClass。
大多数情况下,可以直接使用USomeClass::StaticClass()来避免使用ClassFinder的复杂性。
NavMeshClass = UNavigationMeshBase::StaticClass();
对于跨模块引用,使用ClassFinder更好。
名称:
APylon::APylon(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP) { // Structure to hold one-time initialization struct FConstructorStatics { FName NAME_Navigation; FConstructorStatics() : NAME_Navigation(TEXT("Navigation")) { } }; static FConstructorStatics ConstructorStatics; SpriteCategoryName = ConstructorStatics.NAME_Navigation; }
组件和子物体
ConstructorHelpers::CreateComponent
和ConstructorHelpers::FindComponent被用来创建和获取一个模块。
AWindPointSource::AWindPointSource(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP) { // Structure to hold one-time initialization struct FConstructorStatics { FName NAME_Wind; FConstructorStatics() : NAME_Wind(TEXT("Wind")) { } }; static FConstructorStatics ConstructorStatics; // Property initialization //Create a new component UWindPointSourceComponent* NewComponent0 = ConstructorHelpers::CreateComponent<UWindPointSourceComponent>(this, TEXT("WindPointSourceComponent0")); NewComponent0->PreviewRadiusComponent = NewComponent1; Component = NewComponent0; RootComponent = NewComponent0; //Create a new component UDrawSphereComponent* NewComponent1 = ConstructorHelpers::CreateComponent<UDrawSphereComponent>(this, TEXT("DrawSphereComponent0")); NewComponent1->ShapeColor.R = 173; NewComponent1->ShapeColor.G = 239; NewComponent1->ShapeColor.B = 231; NewComponent1->ShapeColor.A = 255; NewComponent1->AlwaysLoadOnClient = false; NewComponent1->AlwaysLoadOnServer = false; NewComponent1->bAbsoluteScale = true; NewComponent1->AttachParent = NewComponent0; //Find a component on the parent USpriteComponent* NewComponent2 = ConstructorHelpers::FindComponent<USpriteComponent>(this, TEXT("Sprite")); NewComponent2->SpriteCategoryName = ConstructorStatics.NAME_Wind; NewComponent2->AttachParent = NewComponent0; bNoDelete = true; }
查找一个父类的组件一般是不必要的。因为父类的组件都已经被赋值到其属性上,所以直接使用属性就可以访问。如果不在属性中,推荐更改父类的构造函数,而不是使用FindComponet(),这个方法仅仅是用在标准方法无法满足要求的的情况下的。
数组操作
常规方法:
Components.Add(NewComponent0);
添加一个新元素到数组中。
int32 NewArrayIndex1 = ConstructorHelpers::AddArrayElement(Components); Components(NewArrayIndex1) = NewComponent0;