In this article by William Sherif and Stephen Whittle, authorsof the book Unreal Engine 4 Scripting with C ++ Cookbook, we will discuss about how to create C++ classes and structs that integrate well with the UE4 Blueprints Editor. These classes are graduated versions of the regular C++ classes, and are called UCLASS.
(For more resources related to this topic, see here.)
A UCLASS is just a C++ class with a whole lot of UE4 macro decoration on top. The macros generate additional C++ header code that enables integration with the UE4 Editor itself.
Using UCLASS is a great practice. The UCLASS macro, if configured correctly, can possibly make your UCLASS Blueprintable. The advantage of making your UCLASS Blueprintable is that it can enable your custom C++ objects to have Blueprints visually-editable properties (UPROPERTY) with handy UI widgets such as text fields, sliders, and model selection boxes. You can also have functions (UFUNCTION) that are callable from within a Blueprints diagram. Both of these are shown in the following images:
On the left, two UPROPERTY decorated class members (a UTexture reference and an FColor) show up for editing in a C++ class's Blueprint. On the right, a C++ function GetName marked as BlueprintCallable UFUNCTION shows up as callable from a Blueprints diagram.
Code generated by the UCLASS macro will be located in a ClassName.generated.h file, which will be the last #include required in your UCLASS header file, ClassName.h.
The following are the topics that we will cover in this article:
When coding with C++, you can have your own code that compiles and runs as native C++ code, with appropriate calls to new and delete to create and destroy your custom objects. Native C++ code is perfectly acceptable in your UE4 project as long as your new and delete calls are appropriately paired so that no leaks are present in your C++ code.
You can, however, also declare custom C++ classes, which behave like UE4 classes, by declaring your custom C++ objects as UCLASS. UCLASS use UE4's Smart Pointers and memory management routines for allocation and deallocation according to Smart Pointer rules, can be loaded and read by the UE4 Editor, and can optionally be accessed from Blueprints.
Note that when you use the UCLASS macro, your UCLASS object's creation and destruction must be completely managed by UE4: you must use ConstructObject to create an instance of your object (not the C++ native keyword new), and call UObject::ConditionalBeginDestroy() to destroy the object (not the C++ native keyword delete).
In this recipe, we will outline how to write a C++ class that uses the UCLASS macro to enable managed memory allocation and deallocation as well as to permit access from the UE4 Editor and Blueprints. You need a UE4 project into which you can add new code to use this recipe.
Note that although Object will be written in the dialog box, in your C++ code, the C++ class you will deriving from is actually UObject with a leading uppercased U. This is the naming convention of UE4:
UCLASS deriving from UObject (on a branch other than Actor) must be named with a leading U.
UCLASS deriving from Actor must be named with a leading A.
C++ classes (that are not UCLASS) deriving from nothing do not have a naming convention, but can be named with a leading F (for example, FAssetData), if preferred.
Direct derivatives of UObject will not be level placeable, even if it contains visual representation elements like UStaticMeshes. If you want to place your object inside a UE4 level, you must at least derive from the Actor class or beneath it in the inheritance hierarchy.
This article's example code will not be placeable in the level, but you can create and use Blueprints based on the C++ classes that we write in this article in the UE4 Editor.
#pragma once
#include "Object.h" // For deriving from UObject
#include "UserProfile.generated.h" // Generated code
// UCLASS macro options sets this C++ class to be
// Blueprintable within the UE4 Editor
UCLASS( Blueprintable )
class CHAPTER2_API UUserProfile : public UObject
{
GENERATED_BODY()
};
UE4 generates and manages a significant amount of code for your custom UCLASS. This code is generated as a result of the use of the UE4 macros such as UPROPERTY, UFUNCTION, and the UCLASS macro itself. The generated code is put into UserProfile.generated.h. You must #include the UCLASSNAME.generated.h file with the UCLASSNAME.h file for compilation to succeed. Without including the UCLASSNAME.generated.h file, compilation would fail. The UCLASSNAME.generated.h file must be included as the last #include in the list of #include in UCLASSNAME.h.
Right | Wrong |
#pragma once
#include "Object.h" #include "Texture.h" // CORRECT: .generated.h last file #include "UserProfile.generated.h" |
#pragma once
#include "Object.h" #include "UserProfile.generated.h" // WRONG: NO INCLUDES AFTER // .GENERATED.H FILE #include "Texture.h" |
The error that occurs when a UCLASSNAME.generated.h file is not included last in a list of includes is as follows:
>> #include found after .generated.h file - the .generated.h file should always be the last #include in a header
There are a bunch of keywords that we want to discuss here, which modify the way a UCLASS behaves. A UCLASS can be marked as follows:
Any UCLASS that have BlueprintType specified can be added as variables to your Blueprint class diagram's list of variables.
You may be unsure whether to declare your C++ class as a UCLASS or not. It is really up to you. If you like smart pointers, you may find that UCLASS not only make for safer code, but also make the entire code base more coherent and more consistent.
To add additional programmable UPROPERTY to the Blueprints diagrams, see the section on Creating a user-editable UPROPERTY, further in the article.
Each UCLASS that you declare can have any number of UPROPERTY declared for it within it. Each UPROPERTY can be a visually editable field, or some Blueprints accessible data member of the UCLASS.
There are a number of qualifiers that we can add to each UPROPERTY, which change the way it behaves from within the UE4 Editor, such as EditAnywhere (screens from which the UPROPERTY can be changed), and BlueprintReadWrite (specifying that Blueprints can both read and write the variable at any time in addition to the C++ code being allowed to do so).
To use this recipe, you should have a C++ project into which you can add C++ code. In addition, you should have completed the preceding recipe, Making a UCLASS – Deriving from UObject.
UCLASS( Blueprintable )
class CHAPTER2_API UUserProfile : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stats)
float Armor;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stats)
float HpMax;
};
The parameters passed to the UPROPERTY() macro specify a couple of important pieces of information regarding the variable. In the preceding example, we specified the following:
A complete UPROPERTY listing is located at https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Reference/Properties/Specifiers/index.html.
Accessing a UPROPERTY from Blueprints is fairly simple. The member must be exposed as a UPROPERTY on the member variable that you want to access from your Blueprints diagram. You must qualify the UPROPERTY in your macro declaration as being either BlueprintReadOnly or BlueprintReadWrite to specify whether you want the variable to be either readable (only) from Blueprints, or even writeable from Blueprints.
You can also use the special value BlueprintDefaultsOnly to indicate that you only want the default value (before the game starts) to be editable from the Blueprints editor. BlueprintDefaultsOnly indicates the data member cannot be edited from Blueprints at runtime.
UCLASS( Blueprintable, BlueprintType )
class CHAPTER2_API UUserProfile : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stats)
FString Name;
};
The BlueprintType declaration in the UCLASS macro is required to use the UCLASS as a type within a Blueprints diagram.
Navigating Blueprints diagrams is easy. Right-Click + Drag to pan a Blueprints diagram; Alt + Right-Click + Drag to zoom.
UPROPERTY are automatically written Get/Set methods for UE4 classes. They must not be declared as private variables within the UCLASS, however. If they are not declared as public or protected members, you will get a compiler error of the form:
>> BlueprintReadWrite should not be used on private members
So, you've constructed some custom UCLASS intended for use inside of UE4. But how do you instantiate them? Objects in UE4 are reference-counted and memory-managed, so you should not allocate them directly using the C++ keyword new. Instead, you'll have to use a function called ConstructObject to instantiate your UObject derivative. ConstructObject doesn't just take the C++ class of the object you are creating, it also requires a Blueprint class derivative of the C++ class (a UClass* reference). A UClass* reference is just a pointer to a Blueprint.
How do we instantiate an instance of a particular Blueprint from C++ code? C++ code does not, and should not, know concrete UCLASS names, since these names are created and edited in the UE4 Editor, which you can only access after compilation. We need a way to somehow hand back the Blueprint class name to instantiate to the C++ code.
The way we do this is by having the UE4 programmer select the UClass that the C++ code is to use from a simple dropdown menu listing all the Blueprints available (derived from a particular C++ class) inside the UE4 editor. To do this, we simply have to provide a user-editable UPROPERTY with a TSubclassOf<C++ClassName>-typed variable. Alternatively, you can use FStringClassReference to achieve the same objective.
This makes selecting the UCLASS in the C++ code is exactly like selecting a Texture to use. UCLASS should be considered as resources to the C++ code, and their names should never be hard-coded into the code base.
In your UE4 code, you're often going to need to refer to different UCLASS in the project. For example, say you need to know the UCLASS of the player object so that you can use SpawnObject in your code on it. Specifying a UCLASS from C++ code is extremely awkward, because the C++ code is not supposed to know about the concrete instances of the derived UCLASS that were created in the Blueprints editor at all. Just as we don't want to bake specific asset names into the C++ code, we don't want to hard-code derived Blueprints class names into the C++ code.
So, we use a C++ variable (for example, UClassOfPlayer), and select that from a Blueprints dialog in the UE4 editor. You can do so using a TSubclassOf member or an FStringClassReference member, as shown in the following screenshot:
UCLASS()
class CHAPTER2_API UUserProfile : public UObject
{
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Unit)
TSubclassOf<UObject> UClassOfPlayer; // Displays any UClasses
// deriving from UObject in a dropdown menu in Blueprints
// Displays string names of UCLASSes that derive from
// the GameMode C++ base class
UPROPERTY( EditAnywhere, meta=(MetaClass="GameMode"), Category = Unit )
FStringClassReference UClassGameMode;
};
The TSubclassOf< > member will allow you to specify a UClass name using a drop-down menu inside of the UE4 editor when editing any Blueprints that have TSubclassOf< > members.
The MetaClass tag refers to the base C++ class from which you expect the UClassName to derive. This limits the drop-down menu's contents to only the Blueprints derived from that C++ class. You can leave the MetaClass tag out if you wish to display all the Blueprints in the project.
Blueprinting is just the process of deriving a Blueprint class for your C++ object. Creating Blueprint-derived classes from your UE4 objects allows you to edit the custom UPROPERTY visually inside the editor. This avoids hardcoding any resources into your C++ code. In addition, in order for your C++ class to be placeable within the level, it must be Blueprinted first. But this is only possible if the C++ class underlying the Blueprint is an Actor class-derivative.
There is a way to load resources (like textures) using FStringAssetReferences and StaticLoadObject. These pathways to loading resources (by hardcoding path strings into your C++ code) are generally discouraged, however. Providing an editable value in a UPROPERTY(), and loading from a proper concretely typed asset reference is a much better practice.
You need to have a constructed UCLASS that you'd like to derive a Blueprint class from (see the section on Making a UCLASS – Deriving from UObject given earlier in this article) in order to follow this recipe. You must have also marked your UCLASS as Blueprintable in the UCLASS macro for Blueprinting to be possible inside the engine.
Any UObject-derived class with the meta keyword Blueprintable in the UCLASS macro declaration will be Blueprintable.
UCLASS( Blueprintable )
class CHAPTER2_API UUserProfile : public UObject
Keep in mind that you can use the small search box inside the Class Viewer to easily find the UserProfile class by starting to type it in.
Any C++ class you create that has the Blueprintable tag in its UCLASS macro can be Blueprinted within the UE4 editor. A blueprint allows you to customize properties on the C++ class in the visual GUI interface of UE4.
The UE4 code is, typically, very easy to write and manage once you know the patterns. The code we write to derive from another UCLASS, or to create a UPROPERTY or UFUNCTION is very consistent. This article provides recipes for common UE4 coding tasks revolving around basic UCLASS derivation, property and reference declaration, construction, destruction, and general functionality.