Make C in Unreal Engine 4 Easy
Choose your operating system:
Unreal C++ Is Awesome!
This guide is about learning how to write C++ code in Unreal Engine 4 (UE4). Don't worry, C++ programming in Unreal Engine is fun, and actually not hard to get started with! We like to think of Unreal C++ as "assisted C++", because we have so many features to help make C++ easier for everyone.
Before we go on, it's really important that you are already familiar with C++ or another programming language. This page is written with the assumption that you have some C++ experience, but if you know C#, Java, or JavaScript, you should find many aspects familiar.
If you are coming in with no programming experience at all, we have you covered also! Check out our Blueprint Visual Scripting guide and you will be on your way. You can create entire games using Blueprint scripting!
It is possible to write standard C++ code in UE4, but you will be most successful after reading through this guide and learning the basics about the Unreal programming model. We will talk more about that as we go along.
C++ and Blueprint
UE4 provides two methods, C++ and Blueprint Visual Scripting, to create new gameplay elements. Using C++, programmers add the base gameplay systems that designers can then build upon or with to create the custom gameplay for a level or the game. In these cases, the C++ programmer works in a text editor (like Notepad++) or an IDE (usually Microsoft Visual Studio, or Apple's Xcode) and the designer works in the Blueprint Editor within UE4.
The gameplay API and framework classes are available to both of these systems, which can be used separately, but show their true power when used in conjunction to complement each other. What does that really mean, though? It means that the engine works best when programmers are creating gameplay building blocks in C++ and designers take those blocks and make interesting gameplay.
With that said, let us take a look at a typical workflow for the C++ programmer that is creating building blocks for the designer. In this case, we are going to create a class that is later extended via Blueprints by a designer or programmer. In this class, we are going to create some properties that the designer can set and we are going to derive new values from those properties. The whole process is very easy to do using the tools and C++ macros we provide for you.
Class Wizard
The first thing we're going to do is use the Class Wizard within the Editor to generate the basic C++ class that will be extended by Blueprint later. The image below shows the wizard's first step where we are creating a new Actor.
The second step in the process tells the wizard the name of the class you want generated. Here's the second step with the default name used.
Once you choose to create the class, the wizard will generate the files and open your development environment so that you can start editing it. Here is the class definition that is generated for you. For more information on the Class Wizard, follow this link.
#include "GameFramework/Actor.h" #include "MyActor.generated.h" UCLASS() class AMyActor : public AActor { GENERATED_BODY() public: // Sets default values for this actor's properties AMyActor(); // Called every frame virtual void Tick( float DeltaSeconds ) override; protected: // Called when the game starts or when spawned virtual void BeginPlay() override; };
The Class Wizard generates your class with BeginPlay
and Tick
specified as overrides. BeginPlay
is an event that lets you know the Actor has entered the game in a playable state. This is a good place to initiate gameplay logic for your class. Tick
is called once per frame with the amount of elapsed time since the last call passed in. You can do any recurring logic there. However, if you do not need that functionality, it is best to remove it to save yourself a small amount of performance. If you remove it, make sure to remove the line in the constructor that indicated ticking should occur. The constructor below contains the line in question.
AMyActor::AMyActor() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you do not need it. PrimaryActorTick.bCanEverTick = true; }
Making a Property Show up in the Editor
We have our class, so now we can create some properties that designers can set in the Editor. Exposing a property to the Editor is easy with the UPROPERTY
Specifier. All you have to do is put UPROPERTY(EditAnywhere)
on the line above your property declaration, as seen in the class below.
UCLASS() class AMyActor : public AActor { GENERATED_BODY() public: UPROPERTY(EditAnywhere) int32 TotalDamage; ... };
That is all you need to do to be able to edit that value in the Editor. There are more ways to control how and where it is edited. This is done by passing more information into the UPROPERTY()
Specifier. For instance, if you want the TotalDamage property to appear in a section with related properties, you can use the categorization feature. The property declaration below shows this.
UPROPERTY(EditAnywhere, Category="Damage") int32 TotalDamage;
When the user looks to edit this property, it now appears under the Damage heading along with any other properties that you have marked with this category name. This is a great way to place commonly used settings together for editing by designers.
Now let's expose that same property to Blueprint.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Damage") int32 TotalDamage;
As you can see, there is a Specifier to make a property available for reading and writing in Blueprint graphs. There's a separate Specifier, BlueprintReadOnly
, that you can use if you want the property to be treated as const
in Blueprints. There are quite a few options available for controlling how a property is exposed to the Editor. To see more options, follow this link.
Before continuing to the section below, let's add a couple of properties to this sample class. There is already a property to control the total amount of damage this actor will deal out, but let us take that further and make that damage happen over time. The code below adds one designer settable property and one that is visible to the designer but not changeable by them.
UCLASS() class AMyActor : public AActor { GENERATED_BODY() public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Damage") int32 TotalDamage; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Damage") float DamageTimeInSeconds; UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Transient, Category="Damage") float DamagePerSecond; ... };
DamageTimeInSeconds
is a property the designer can modify. The DamagePerSecond
property is a calculated value using the designer's settings (see the next section). The VisibleAnywhere
Specifier marks that property as viewable but not editable. The Transient
Specifier means that it won't be saved or loaded from disk; it is meant to be a derived, non-persistent value, so there is no need to store it. The image below shows the properties as part of the class defaults.
Setting Defaults in the Constructor
Setting default values for properties in a constructor works the same as your typical C++ class. Below are two examples of setting default values in a constructor and are equivalent in functionality.
AMyActor::AMyActor() { TotalDamage = 200; DamageTimeInSeconds = 1.0f; } AMyActor::AMyActor() : TotalDamage(200), DamageTimeInSeconds(1.0f) { }
Here is the same view of the properties after adding default values in the constructor.
In order to support per-instance designer-set properties, values are also loaded from the instance data for a given object. This data is applied after the constructor. You can create defaults based off of designer-set values by hooking into the PostInitProperties()
call chain. Here is an example of that process where TotalDamage
and DamageTimeInSeconds
are designer-specified values. Even though these are designer specified, you can still provide sensible default values for them, as we did in the example above.
If you do not provide a default value for a property, the engine will automatically set that property to zero, or null in the case of pointer types.
void AMyActor::PostInitProperties() { Super::PostInitProperties(); DamagePerSecond = TotalDamage / DamageTimeInSeconds; }
Here is the same view of the properties after we have added the PostInitProperties()
code that you see above.
Hot Reloading
Here is a cool feature of Unreal that you might be surprised about if you are used to programming C++ in other projects. You can compile your C++ changes without shutting down the Editor! There are two ways to do this:
-
With the Editor still running, go ahead and build from Visual Studio or Xcode like you normally would. The Editor will detect the newly compiled DLLs and reload your changes instantly!
If you are attached with the debugger, you'll need to detach first so that Visual Studio will allow you to build.
-
Or, simply click the Compile button on the Editor's main toolbar.
You can use this feature in the sections below as we advance through the tutorial.
Extending a C++ Class via Blueprints
So far, we have created a simple gameplay class with the C++ Class Wizard and added some properties for the designer to set. Now, let's take a look at how a designer can start creating unique classes from our humble beginnings here.
The first thing we are going to do is create a new Blueprint class from our AMyActor
class. Notice in the image below that the name of the base class selected shows up as MyActor instead of AMyActor. This is intentional and hides the naming conventions used by our tools from the designer, making the name friendlier to them.
Once you choose Select, a new default named Blueprint class is created for you. In this case, I set the name to CustomActor1 as you can see in the snapshot of the Content Browser below.
This is the first class that we are going to customize with our designer hats on. First thing we are going to do is change the default values for our damage properties. In this case, the designer changed the TotalDamage
to 300 and the time it takes to deliver that damage to 2 seconds. This is how the properties now appear.
Our calculated value does not match what we would expect. It should be 150 but it is still at the default value of 200. The reason for this is that we are only calculating our damage per second value after the properties have been initialized from the loading process. Runtime changes in the Editor are not accounted for. There is a simple solution to this problem because the Engine notifies the target object when it has been changed in the Editor. The code below shows the added hooks needed to calculate the derived value as it changes in the Editor.
void AMyActor::PostInitProperties() { Super::PostInitProperties(); CalculateValues(); } void AMyActor::CalculateValues() { DamagePerSecond = TotalDamage / DamageTimeInSeconds; } #if WITH_EDITOR void AMyActor::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { CalculateValues(); Super::PostEditChangeProperty(PropertyChangedEvent); }
0 Response to "Make C in Unreal Engine 4 Easy"
Post a Comment