Hello World for C++

Before we begin to create an in-depth game project like Barrel Hopper, we will first return to the good old Hello World idea. We are going to be creating something very similar to what we created in Chapter 1, Introduction to Unreal Engine 4 yet, this time, purely in C++! We can start by creating a new C++ project. Open Unreal Engine 4.10 via the Epic Games Launcher then select the New Project tab like we did before, however this time we are going to be choosing the C++ tab. From the collection of project templates, select Basic Code.

Hello World for C++

Call this project Hello Code. There will be a small waiting period while the engine prepares your project. Once finished you will be presented with an editor window and a Visual Studio project will have opened. The first thing we are going to do is add a new code class to our project. Do this by selecting New C++ Class… from the File dropdown located in the top left-hand corner of the main editor window.

This will open the class creation wizard. You will see that it prompts you to choose a parent class for the new object. We are going to be creating another hello sphere, this time using C++. As we are going to be creating an object that exists in the game world as an interactable and visible entity, we need to extend this object from the AActor base class. The reason for this will be explained soon.

Tick the checkbox Show All Classes in the top right-hand side of the class creation wizard then select Actor from the shown classes. You can also use the search bar provided at the top of the class creation wizard to find the desired base class. Hit the green Next button at the bottom of the wizard and you will be asked to name the class. Call this class HelloSphere then click the green Create Class button. The wizard will then generate an .h and .cpp file for us.

Exploring your first code class

You will notice that the source for the new HelloSphere object has been added to your Visual Studio project automatically and can be found under the source filter Source | HelloCode.

Exploring your first code class

As you can see, it has been included alongside your project source files and a default HelloCodeGameMode object. Before we start to write anything, let's first break down what is presented to you by default so we can better understand the workings of an UE Object. Let's address the HelloSphere.h header file. There is not too much here to begin with, you should be presented with the following:

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once

#include "GameFramework/Actor.h"
#include "HelloSphere.generated.h"

UCLASS()
class HELLOCODE_API AHelloSphere : public AActor
{
    GENERATED_BODY()

public:
    // Sets default values for this actor's properties
    AHelloSphere();

    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

    // Called every frame
    virtual void Tick(float DeltaSeconds) override;
};

Accommodating for the Unreal Build Tool

As you can see, #pragma once is specified by default, this is a pre-processor instruction informing the compiler to only compile this header file once when building the project. The first thing that you may notice is the include list for the header file. As you can see, the header file for the object's parent class (AActor) is included. Underneath this however is #include "HelloSphere.generated.h". This line is very important as this allows the Unreal Build Tool (UBT) to generate code for our custom object.

The UBT is a very core aspect of the Unreal C++ workflow. It is through this tool that the engine is able to create associations between our custom objects and the core facilities of the engine. You may have seen something similar with other engines. The UBT does its work during something called a Pre-Compile stage, which makes sense as it generates code based on what is already in your object, before they are compiled by the standard compiler. How we interact with UBT will be detailed as we continue to learn about using C++ with UE4.

Pre-Compile macros and you

Unlike a standard C++ object, you will see some macros being used outside and inside the class definition. Macros are simply keywords that are swapped out for previously constructed code at compile time. In our case, these macros are going to be picked up by the UBT and replaced with generated code.

The first one that we encounter is UCLASS(), located just before the definition of the object. This macro is responsible for informing the engine of this object and any meta data associated with this object. As you can see, this macro includes an empty parameter list denoted by (), it is with this that you may also include something called specifiers. Specifiers act like parameters for the macro and will change how the class is interpreted by the engine. We will be utilizing these specifiers later in the chapter. For now we can leave the UCLASS() macro empty.

Predominantly, the presence of these macros are found in object header files with the Class definition, as it is here where you will be detailing most of the association between your code objects and UE4, which is why they are so prolific in this small 9-line class definition. The other two macros present are HELLOCODE_API, found within the class definition itself, and GENERATED_BODY().

HELLOCODE_API is used to define code set to which this object belongs and is used as an organizational tool when building the project. The macro itself will always follow the same format [ProjectName]_API, all capitalized. In this case the line class HELLOCODE_API AHelloSphere : public AActor can be interpreted as, this a class AHelloSphere that inherits from AActor publically that is part of the HelloCode project API.

GENERATED_BODY() is simply a macro that allows for code generation to be inserted within the body of the object by the UBT itself before the main compile stage.

Breaking down the rest of the header file

The rest of the object is fairly simple, it includes a default constructor AHelloSphere() and two virtual functions, BeginPlay() and Tick(). BeginPlay() is called when the actor is spawned in the level and functions in exactly the same way as Event BeginPlay in Blueprint. This function has been declared as virtual in the AActor base class, therefore we can override this function to execute our own functionality when this actor is spawned in a level. The other function Tick() is also virtual and provides us with the delta tick for the current frame via the float DeltaSeconds input parameter.

These two functions are included by default by the class wizard, as it is assumed that, at the very least, these two functions will be overridden by all custom objects that inherit from the AActor base class. Let's now look at the HelloSphere.cpp file. You are provided with basic function definitions for the default methods that were generated by the C++ class wizard.

The default constructor and include list

Before we begin to break down each of these function definitions, let's first look at the include list for this .cpp:

#include "HelloCode.h"
#include "HelloSphere.h"

As you can see, the include list for the .cpp of this object also includes the header file for the project (HelloCode.h). This provides access to the engine code base within this cpp, meaning we can make use of things such as object creators, object finders, and logging, among other very important features. Ok, let's now take a look at the definition for the default constructor of our AHelloSphere object:

// Sets default values
AHelloSphere::AHelloSphere()
{
    // Set this actor to call Tick() every frame.  
    // You can turn this off to improve performance.
    PrimaryActorTick.bCanEverTick = true;
}

When working with UE objects it is within the default constructor that you will specify a majority of your object initialization functionality, as it is here that you are able to populate and initialize your object components. The reason we do this in the constructor and not in BeginPlay() is we wish the components to be added and initialized before our project is playing at what we could call Editor time. This means our object's components will be created and initialized when the project is run. We will then be able to work with these components within the editor, much like we have done so far in this book.

Within the definition of the default constructor (AHelloSphere::AHelloSpehre()) you will note the inclusion of PrimaryActorTick.bCanEverTick = true. This line flags this actor to be scrutinized for Tick calls. It is very important to include this line for any objects that you wish to Tick during runtime.

Virtual functions and calling the parent

Now let's look at the two virtual functions that have been provided by default:

// Called when the game starts or when spawned
void AHelloSphere::BeginPlay()
{
   Super::BeginPlay();
}

// Called every frame
void AHelloSphere::Tick(float DeltaTime)
{
   Super::Tick(DeltaTime);
}

You may have noticed that both of the definitions for the virtual functions include the line Super::[FunctionName]. This line of code executes the parent functionality of the same function. This is a very important tool as it means you are able to override parent functions without worrying about missing any core functionality that takes place in that parent call. This emphasizes the previous point of extensibility in C++. You are able to override the functions found in UE objects, call them, and write your own extension functionality.

Adding components and object creators

The first thing we want to do is add components to our new object so that we may duplicate the Hello Sphere functionality we had in Chapter 1, Introduction to Unreal Engine 4, Components are created via a template function titled CreateDefaultSubobject(). There are many object creation methods such as CreateDefaultSubobject() that will be used when working with the engine. One of the main reasons we will use these object creation methods is so that we utilize Unreal Engine's memory management systems.

These object creation methods will invoke UE4's memory managers, identifying and allocating the most efficient memory location for our objects. They will also register the UObjects we are trying to create with the Unreal Garbage Collector. The garbage collector automatically cleans up any UObjects that are no longer being referenced or have fallen out of scope. Because of this we do not have to worry about memory leaks and inefficient memory allocations.

Now let's begin writing some C++ code. We are going to be adding all of the components needed to recreate the HelloSphere from Chapter 1, Introduction to Unreal Engine 4 We are going to require a UStaticMeshComponent for our sphere visual mesh, a USphereComponent so we may check for overlap events, a UParticleSystemComponent for our fire particles, and a UTextRenderComponent for our HelloWorld text. When adding components to an object we do not always need to include a code side handle in our class member variables. This is because CreateDefaultSubobject() will register our components with the base class. Unless we wish to reference a component outside of the class constructor, we can save on memory and not include a handle to the component in our class definition.

The only component that we will need access to after initialization is the UTextRenderComponent. We will want to change the text of the component when the default pawn overlaps the sphere component of the AHelloSphere actor. Navigate to HelloSphere.h now and add a handle to this component in our AHelloSphere class definition as a member variable:

protected:
class UTextRenderComponent* TextRenderComponent;

It's important to note that this has not created the component, we have merely added a handle in the form of a pointer that is of type UTextRenderComponent. We have also specified this handle to be encapsulated at a protected level as this handle will not be accessed outside of this object. You may have noticed the keyword class being used here. This is known as inline forward declaration. It is always advised to forward declare object types that may not be known to your class definition. This is to reduce including overheads in our .h files. Before we populate this handle with an initialized component, let's first create our other required components and initialize those with the appropriate values.

Navigate back to HelloSphere.cpp and within the definition of our default constructor (AHelloSphere::AHelloSphere()) add the following code:

// Our root component will be a sphere component that will inform us of overlaps and collisions
USphereComponent* SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("RootComponent"));

RootComponent = SphereComponent;

// Assign properties to sphere component
SphereComponent->InitSphereRadius(220.0f);

SphereComponent->
SetCollisionProfileName(TEXT("OverlapAllDynamic"));

Here we are creating and initializing the sphere component that will be used to detect overlaps and collisions with the HelloSphere actor. As you can see, here we are utilizing the CreateDefaultSubobject() template function. This function will create a component of the templated type and return a handle to the newly created component. You can specify the component name as a parameter to this function via the TEXT macro. We are then assigning the newly created component into a temporary handle so we may access the component and change some of its properties. It is also important to note that we set the SphereComponent as our RootComponent by assigning it to the provided RootComponent variable handle.

Instead of using a Details panel to change properties on a component, we have instead used member functions and variables to set these values. In the previous example, we are setting the sphere radius to 220.0f via InitSphereRadius() and then setting the collision profile to OverlapAllDynamic via SetCollisionProfileName(). The latter takes in an FName representing the collision profile you wish to change to. It will make any changes to the collision settings required to match this profile. This is very similar to what you would do in the collision section of the Details panel.

Tip

I would strongly recommend that every time you are working with an Unreal Object for the first time, you research that object using the Unreal Engine Reference API found here at https://docs.unrealengine.com/latest/INT/API/index.html.

Construction helpers and object finders

The next thing we are going to do is add our static mesh component that will be used to draw the sphere geometry of the object. We need to create a UStaticMeshComponent and then assign it a static mesh asset we have in our content browser. Unlike Blueprint, we do not have access to the drag-and-drop functionality of the content browser to create asset associations. Instead we must use a template object provided by the Engine.h header file (this header is included in the HelloCode.h by default). This template object is called a FObjectFinder and is part of the ConstructorHelpers namespace. You can initialize this object with the type of asset you wish to find as the template type, then provide a path to the asset you wish to populate the object with as a FName parameter to the object constructor. The following is the code that creates the appropriate static mesh component then uses a FObjectFinder object to assign the correct asset. Add the following code to the default constructor definition now:

// Create and attach a sphere mesh
UStaticMeshComponent* SphereVisual = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SphereMesh"));
SphereVisual->AttachTo(RootComponent);

// Assign mesh to static mesh component through construction helper
ConstructorHelpers::FObjectFinder<UStaticMesh> SphereAsset(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));


// Adjust properties of the mesh if mesh asset was found
if (SphereAsset.Succeeded())
{
    SphereVisual->SetStaticMesh(SphereAsset.Object);
    SphereVisual->SetRelativeLocation(FVector(0.0f, 0.0f, -50.0f));
}

Here we have created a temporary handle (SphereVisual) to the UStaticMeshComponent. We then call AttachTo() on this newly created component. This function takes in a handle to the component we wish to attach to, in our case this is the RootComponent handle that currently points to the SphereComponent we created earlier. This attaching is the same as dragging one component onto another in the Components panel of the Blueprint Editor.

Next we create an FObjectFinder with the template type of UStaticMesh called SphereAsset. We then use the constructor of the FObjectFinder to initialize the finder with the path to a sphere asset in our content browser. This will then invoke the FObjectFinder to locate and assign the asset at the provided path to itself.

When providing the path to any given asset in the content browser, the easiest way is navigating to the asset in the Content Browser, right-clicking the desired asset, and selecting Copy Reference. This method can be seen as follows, along with the yielding result:

Construction helpers and object finders

This will yield—StaticMesh'/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere.

Everything following the object type surrounded by the (') character is the path you must provide to the FObjectFinder constructor.

Following the construction of the FObjectFinder we ensure that this asset assignment was successful. We do this via the Succeeded() method. The FObjectFinder object includes the function Succeeded(), which returns a bool that represents whether the asset path provided at construction was valid and the asset has been found. If this function returns true, we assign the found static mesh to the UStaticMeshComponent we just created and adjust its relative position slightly.

We can assign the Mesh asset via the Object member of FObjectFinder. This member will be of the template type specified when creating the FObjectFinder, in this case UStaticMesh. We can use Object as an input parameter to the SetStaticMesh() function of the UStaticMeshComponent. We then slightly change the relative location of the sphere Mesh with SetRelativeLocation(), this is so that it sits in the center of our root sphere component. It is important to note that we are adjusting the relative location of the component. This means the position adjustment will be maintained as the HelloSphere object as a whole travels through world space.

Building the code

Alright! Now let's build our code for the first time. You may have noticed that our open Visual Studio project is not currently running our Editor (as no project instance is running). Close your UE Editor now but leave Visual Studio open. Ensure the HelloCode project is set as the start-up project by right-clicking on the project in the Solution Explorer and selecting Set as Startup Project…, also ensure that your Solution Configuration is set to Development Editor and Solution Platforms is set to Win64. You should see the following at the top of your IDE window:

Building the code

Now, build the project by clicking the Local Windows Debugger button or pressing F5 and behold the glory of your (and Epic's) compiled code! If your project does not build cleanly, address the Output panel of the IDE for any errors or warnings you need to clear up.

Upon successful compilation you will be presented with the Level Editor, as you would if you had simply opened the project via the Project Browser. There will be one key difference however, our new Hello Sphere object will be included in the class lists! To see our C++ classes in the content browser there is a small button that will show or hide the sources panel. It is highlighted in the following image:

Building the code

As you can see, our HelloSphere object can be located under the C++ Classes | HelloCode filter. Drag and drop our old friend into your level now and you will be presented with a sphere Mesh and sphere collider! Select this HelloSphere entry in the content browser and drag it into the level scene!

Adding Fire Particles and Hot Compilation

Ok, now we are going to finish creating the AHelloSphere object. We are going to be making edits to the code, however do not stop running the build of our project from the IDE. We are going to be Hot Compiling the following code modifications. What that is will be detailed soon. For now, let's set the HelloSphere on fire!

Setting the sphere on fire

We are going to set the sphere on fire by adding a UParticleSystemComponent to our object and then assigning this component a particle template in the same way we assigned a sphere mesh to the UStaticMeshComponent. Navigate to HelloSphere.cpp and add the following code to the AHelloSphere::AHelloSphere() constructor:

// Create the fire particle system
UParticleSystemComponent* FireParticles = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("FireParticles"));

FireParticles->AttachTo(SphereVisual);
FireParticles->bAutoActivate = true;

// Assign fire particle system to component
ConstructorHelpers::FObjectFinder<UParticleSystem> FireVisual(TEXT("/Game/StarterContent/Particles/P_Fire.P_Fire"));

if (FireVisual.Succeeded())
{
    FireParticles->SetTemplate(FireVisual.Object);
}

We are creating the component via CreateDefaultSubobject as per usual. We are then attaching the newly created UParticleSystemComponent to the UStaticMeshComponent we created earlier. This is because we wish the particle system to move with the mesh when translated. We also ensure that the bAutoActivate member of UParticleSystemComponent is set to true as we want it to start playing as soon as the object is spawned in the level. We then use another FObjectFinder, this time of type UParticleSystem, to retrieve the P_Fire particle system template provided by the Unreal Starter content.

The next step is very similar to the assignment of the mesh asset to UStaticMeshComponent. Again we use the Succeeded() function to gauge the success of asset retrieval. If it succeeds, we provide the Object member of the FObjectFinder FireVisual to the SetTemplate() function of the UParticleSystemComponent. Because we created FireVisual with UParticleSystem as the template type, the Object member will be of type UParticleSystem, thus it is compatible as an input parameter for the SetTemplate() function. This is a great example of effective template use when working with C++ and UE4.

Hot Compilation

Now that we have made a change to the codebase, let's quickly demonstrate the power of Hot Compilation. Hot Compilation allows the developer to make changes to the codebase of an object without having to rebuild the entire project. To perform a hot compile, you must press the Compile button located in the Toolbar of the Level Editor. Ensure you have the HelloSphere object present in the viewport and then press the Compile button. You will notice a small popup appear in the bottom right-hand side of the screen that states Compiling C++ Code…. When the code compilation is successful you will see the Hello Sphere object in the level update to the latest version of the compiled asset! How can we tell the object has been updated? Well, it should not be aflame like so:

Hot Compilation

If the object has not updated properly, ensure that the code compiled successfully. If it did and the object has still not updated, simply re-drag the HelloSphere object into the scene and delete the original. This Hot Compilation feature is a very powerful tool as we do not have to worry about re-building the entire project whenever we make small changes to the codebase. However, large refactors or additions to the codebase will require a full re-compile from Visual Studio, especially with regards to changes made to header files, as this may have a direct impact on how the object associates with the engine. If you do experience any strange bugs after a Hot Compilation, be sure to recompile the project to see whether the bug still remains.

Hello world text and receiving events through delegates

Now it is time to finally add the 3D text that gives AHelloSphere a little personality. If you remember, the way we did this in Blueprint was simply by changing the text of a TextRenderComponent upon receiving an OnBeginOverlap event. We have to do this a little differently in code, instead of overriding the event function call in our AHelloSphere object or waiting for an event to be hit, we are going to be creating a function and binding it to the event delegate. The reason for this will be explained soon, for now let's add our UTextRenderComponent to the object.

Adding the 3D text

Navigate back to HelloSphere.cpp and, within the constructor definition (AHelloSphere::AHelloSpehre()) underneath the code we just added for the particle system, add the following code:

// Initialize Text Render component
TextRenderComponent = CreateDefaultSubobject<UTextRenderComponent>(TEXT("Text"));

TextRenderComponent->AttachTo(SphereVisual);

TextRenderComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 110.0f));

TextRenderComponent->SetHorizontalAlignment(EHTA_Center);
TextRenderComponent->SetYScale(2.0f);
TextRenderComponent->SetXScale(2.0f);
TextRenderComponent->SetVisibility(true);
TextRenderComponent->SetText(NSLOCTEXT("AnyNs", "Any", "HelloWorld"));

Here we create the UTextRenderComponent via the CreateDefaultSubobject() function, then attach it to the UStaticMeshComponent using AttachTo() and the SphereVisual handle. We then change some of the properties of the text render component. We want to have the text float above the sphere, thus we are changing the relative offset of the text by 110.0f on the Z axis via SetRelativeLocation(). We then want to ensure that the text aligns so that it is centered around its location in 3D space. We do this by changing the alignment type via SetHorizontalAllignment() to EHTA_Center. We then change the scale of the text and ensure the text is visible.

The way we set the text is fairly interesting, however we do this by using the macro NSLOCTEXT. This macro creates and returns an FText object for us to parse into the SetText() function. We only wish our text to say HelloWorld so why have we also provided the strings AnyNS and Any? In short, Any is a key and AnyNS is a namespace.

FText as an object has been designed with localization support in mind. This means you are able to easily localize your projects to whichever country you are building for. Because of this, when creating an FText object you need to provide not only a string value to write but also a key. The key will be used by the localization tools to identify the text value, even after the language has changed. Meaning that HelloWorld could be changed to こんにちは世界 if you were building to Japan via the localization tools, but the key Any will remain the same. Namespaces are simply used to group keys together so you may localize one namespace grouping of text but not another. If you do not wish to use FText you can use an FString object or FName object via the TEXT macro but this will result in a warning from the compiler.

Tip

If you want to learn more about FText and the localization tools, go here https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/StringHandling/FText/index.html.

Ok, perform another hot compile and see the new text floating above our spherical friend:

Adding the 3D text

Delegates and Events

Let's look into how we are going to be receiving the BeginOverlap event in our AHelloSphere code object. We have to add code to both our class definition in the HelloSphere.h file as well as the default constructor definition in the HelloSphere.cpp. We are going to be creating two functions MyOnBeginOverlap() and MyOnEndOverlap(). We are then going to provide these two functions to the corresponding delegates found in the AActor base class. Delegates are objects that act in a similar way to Event Dispatchers in Blueprint. We are able to provide multiple function handles to a delegate and have them all invoked when the delegate is instructed to broadcast.

Delegate objects are declared with a given function signature. A function signature is what defines the make-up of a function, for example the function void Multiply(int a, int b) has a function signature that looks like this void function (int, int) or void Function ( <Param1>, <Param2>). Meaning a function that takes in two integer numbers as input parameters and does not return anything. You could then create a delegate called MathDelegate specifying this function signature at declaration. You would then be able to bind Multiply() to MathDelegate as well as any other functions with a matching function signature. When the MathDelegate is instructed to Broadcast Multiply(), any other bound functions will be invoked.

We can see the benefits of this delegate system when we utilize those provided by the AActor base class. For us to have the functionality to execute when an actor overlaps our sphere component, we need to create a function that we will bind to a delegate called OnActorBeginOverlap. We are then going to have to do the same thing with a different function for the OnActorEndOverlap delegate. The reason this has to be done via delegates instead of say, virtual functions, is so that we may have multiple functions bound to these delegates throughout the object's hierarchy, including those declared in Blueprints. You may have guessed already that whenever you add an event node to a blueprint graph you are really binding a new function to a backend code delegate of a similar name!

Let's first create the functions we are going to bind by adding the following code to the HelloSphere.h file within the class definition, just above the declaration of the UTextRenderComponent handle under the protected keyword:

// On Overlap implementation
UFUNCTION()
void MyOnBeginOverlap(AActor* OtherActor);

// On End Overlap implementation
UFUNCTION()
void MyOnEndOverlap(AActor* OtherActor);

Here we have created two functions that have the same signature void function (AActor*). This is important as this is the signature of the OnActorBeginOverlap and OnActorEndOverlap delegates. We have also encountered a new pre-compiler macro UFUNCITON(). The UFUNCITON() macro lets us inform the engine of any crucial functions that we wish the engine to know about. We may also specify any unique properties of the function via specifiers but let's not get ahead of ourselves. The UFUNCTION() macro is present here as it is required if we wish to bind these functions to any delegates.

Next we need to actually bind these functions to the aforementioned delegates. Let's do this now by adding the following code to the definition of the constructor in the HelloSphere.cpp underneath the UTextRenderComponent initialization:

// Bind delegates
OnActorBeginOverlap.AddDynamic(this, &AHelloSphere::MyOnBeginOverlap);
OnActorEndOverlap.AddDynamic(this, &AHelloSphere::MyOnEndOverlap);

What we are doing here is adding the functions we just declared to the corresponding delegates via the AddDynaminc function. This function takes in a handle to the object that will invoke the function we are binding, and a handle to the function that is to be called. We are doing this via the this keyword and the address of the respective function.

The next thing we need to do is define the functions we just bound so they perform meaningful functionality. We can do this by adding the following code to the HelloSphere.cpp. Note that these function definitions are outside the scope of the constructor definition:

void AHelloSphere::MyOnBeginOverlap(AActor* OtherActor)
{
   FString outputString;
   outputString = "Hello " + OtherActor->GetName() + "!";
   TextRenderComponent->SetText(FText::FromString(outputString));
}

void AHelloSphere::MyOnEndOverlap(AActor* OtherActor)
{
   TextRenderComponent->SetText(NSLOCTEXT("AnyNs", "Any", "HelloWorld"));
}

The function MyOnBeginOverlap() will now concatenate an FString based on Hello, the name of the offending actor, and ! will then convert this string to an FText value via FText::FromString. It will then set the text value of the UTextRenderComponent to the resultant FText value. MyOnEndOverlap() simply sets the text back to HelloWorld in the same way we did upon the initial creation of the UTextRenderComponent.

Hot compile our new changes and run the project! When you encroach on the Hello sphere it will greet our pawn object. You should see something similar to the following:

Delegates and Events

Polishing the sphere

There are a few more things we need to do before our C++ Hello Sphere is the same as the Blueprint one we made earlier. We need to add that Unreal Factor and give our sphere that nice metallic sheen that made it glisten in the light of its own fire.

Changing materials via C++

We are going to have to change a property of the UStaticMeshComponent we created after we have set the mesh of the object. This is very easy to do, all we need is another FObjectFinder that will be able to find the material object we require, then simply set the material value of the UStaticMeshComponent. This can be done by modifying our original UStaticMeshComponent initialization code in the HelloSphere.cpp within the constructor definition, to appear as follows:

// Assign mesh to static mesh component through constructions helper
ConstructorHelpers::FObjectFinder<UStaticMesh> SphereVisualAsset(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));

ConstructorHelpers::FObjectFinder<UMaterial> SphereMaterial(TEXT("/Game/StarterContent/Materials/M_Metal_Burnished_Steel.M_Metal_Burnished_Steel"));

// Adjust properties of the mesh if mesh was created successfully
if (SphereVisualAsset.Succeeded() && SphereMaterial.Succeeded())
{
    SphereVisual->SetStaticMesh(SphereVisualAsset.Object);
    SphereVisual->SetMaterial(0, SphereMaterial.Object);
    SphereVisual->SetRelativeLocation(FVector(0.0f, 0.0f, -40.0f));
} 

As you can see, all we needed to do was create another FObjectFinder of type UMaterial and ensure we check the result of the retrieval of this asset alongside that of the UMesh, and then simply set the material via the SetMaterial() function. It is important to note that the first parameter of the SetMaterial() function is the index of the material you wish to change. This is important when setting materials of meshes that have multiple material indexes.

With the previous code in place and compiled, we can finally say hello to a finished HelloSphere made entirely in C++!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.38.142