参见:https://docs.unrealengine.com/latest/CHN/Programming/UnrealArchitecture/Reference/Classes/index.html
The most basic form of a UObject constructor is shown below.
AMyClass::AMyClass(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { }
Obviously, this constructor does not perform any initialization. In fact, it has no effect on the object being created whatsoever. However, you will notice the FObjectInitializer
parameter that is passed in to the constructor. This structure initializes the properties from an archetype or class default object (CDO) after the constructor returns. It is used to guarantee that every UObject
that is constructed has the properties initialized. The FObjectInitializer
can be used as demonstrated in the following constructor to skip any initialization of properties present in the constructor when they have already been set by an Archetype or CDO.
AUDKEmitterPool::AUDKEmitterPool(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { // Property initialization MaxActiveEffects = 200; SMC_MIC_ReductionTime = 2.0; IdealStaticMeshComponents = 200; IdealMaterialInstanceConstants = 200; } AUTDemoHUD::AUTDemoHUD(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , SomeNonProperty("Hi there") { // Non-property initialization SomeOtherNonProperty = 26; // Property initialization SomeProperty = 30; SomeOtherProperty = "My message"; }
Asset References
Ideally asset references in classes do not exist. Hardcoded asset references are brittle and the movement has been toward using Blueprints for configuration of asset properties. However, this is fully supported. We do not want to search for assets every time we construct an object, so these searches are only done once. This is accomplished via a static struct which ensures that we do our asset searches only once:
ConstructorHelpers::FObjectFinder
finds a reference to the specified UObject
using StaticLoadObject
. This is generally used to reference assets stored in content packages. Reports failure if the object is not found.
ATimelineTestActor::ATimelineTestActor(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { // 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; }
Class References
ConstructorHelpers::FClassFinder
finds a reference to the specified UClass
. Reports failure if the class is not found.
APylon::APylon(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { // 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; }
In many cases, you can just use USomeClass::StaticClass()
and skip the complexity of the ClassFinder altogether. For example, you can use the method below in most circumstances:
NavMeshClass = UNavigationMeshBase::StaticClass();
For cross-module references, it is probably better to use the ClassFinder method.
Names
APylon::APylon(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { // Structure to hold one-time initialization struct FConstructorStatics { FName NAME_Navigation; FConstructorStatics() : NAME_Navigation(TEXT("Navigation")) { } }; static FConstructorStatics ConstructorStatics; SpriteCategoryName = ConstructorStatics.NAME_Navigation; }
Components and Sub-Objects
Creating sub-objects, especially components, and modifying sub-objects belonging to parent classes also makes use of constructor helpers. The ConstructorHelpers::CreateComponent
and ConstructorHelpers::FindComponent
helpers can be used to create and find components, respectively.
AWindPointSource::AWindPointSource(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { // 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; }
Array Manipulation
Arrays can be modified and manipulated using the standard methods belonging to the array.
ExampleArray.Add(NewComponent0);
In the event this is not desired, helper templates for adding items, expanding the array, and clearing the array are provided. For instance, to add a new component to the Components
array, the following can be used.
int32 NewArrayIndex1 = ConstructorHelpers::AddArrayElement(ExampleArray);
ExampleArray(NewArrayIndex1) = NewComponent0;