terça-feira, 18 de agosto de 2020

TutoProjectHUD class: Using C++ pointers

In this article, we are going to create the TutoProjectHUD class which is responsible for drawing the game state variables on the screen. However, these variables belong to the TutoProjectGameMode class. We will need to use a pointer to access the public variables and functions of the TutoProjectGameMode class within the TutoProjectHUD class.

First, let's create the TutoProjectHUD class. In the Content Browser, access the TutoProject folder that is inside the C++ Classes folder. Right-click on a free space and choose the New C++ Class... option as shown in the image below.


On the next screen, you have to choose the parent class that will be used as the type for the new class. Scroll through the options until you find the HUD class. Select the HUD class and click the Next button. 


In the Name field, write TutoProjectHUD. In the Path field, keep the default project folder. Click the Create Class button. 


In this article, we will focus only on how to create a pointer to the TutoProjectGameMode class and how to obtain the reference of the Game Mode being used by the game. In another article, we will see the functions used to draw on the screen.

A pointer stores a memory address. We can use a pointer to reference an instance of a class. You define that a variable is a pointer using the * operator next to the variable's type. The line of code below shows the definition of a variable called TutoProjectGameMode which is a pointer to an instance of the ATutoProjectGameMode class. 
ATutoProjectGameMode* TutoProjectGameMode;
The line above defined a pointer but it is not yet storing a reference to an instance of the ATutoProjectGameMode class. In the BeginPlay() function, we will get a reference to the ATutoProjectGameMode class instance being used by the game and store it in our pointer.

Open the file TutoProjectHUD.h, add the label protected: and the declarations of the TutoProjectGameMode pointer and the BeginPlay() function as shown in the code below. 
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "TutoProjectHUD.generated.h"

UCLASS()
class TUTOPROJECT_API ATutoProjectHUD : public AHUD
{
	GENERATED_BODY()

protected:

	class ATutoProjectGameMode* TutoProjectGameMode;

	virtual void BeginPlay() override;
		
};
Note that there is the keyword class before the definition of the TutoProjectGameMode pointer. This was necessary because the ATutoProjectHUD class does not know the ATutoProjectGameMode class. It is a way to inform the compiler that there is a class called ATutoProjectGameMode and that the class definition will be found later during compilation. This is known as Forward Declaration.

Instead of using the keyword class, you could add a #include "TutoProjectGameMode.h" at the beginning of the file, as this header file contains the definition of the ATutoProjectGameMode class. But, whenever possible, avoid adding more #include in header files (.h). It is best to place them in the implementation files (.cpp).

The TutoProjectHUD.cpp file must have this content:
#include "TutoProjectHUD.h"
#include "TutoProjectGameMode.h"

void ATutoProjectHUD::BeginPlay()
{
  Super::BeginPlay();

  TutoProjectGameMode = GetWorld()->GetAuthGameMode<ATutoProjectGameMode>();
}
Let's analyze the line responsible for obtaining and storing the Game Mode reference in our pointer:
  • TutoProjectGameMode : This is our pointer variable.
  • GetWorld() : This function returns a pointer to an instance of the UWorld class that represents the current map.
  • -> : When you have a pointer, you need to use the -> operator to access the functions and variables of an instance. 
  • GetAuthGameMode<ATutoProjectGameMode>() : This function returns a pointer to the Game Mode instance being used by the map. The function uses a C++ template parameter, which is the class being passed between < >.

The GetAuthGameMode function will attempt to Cast the Game Mode to the ATutoProjectGameMode class. Cast is type conversion. This conversion will only work if the map is using the Game Mode TutoProjectGameMode. If you are not familiar with Game Mode, see the link below:

The next image shows how the BeginPlay() function/event would be if it had been done in Blueprints.


For teaching purposes, I put the class name used in the Cast node as ATutoProjectGameMode to facilitate association with the C++ code. But remember that the prefix A is an Unreal Engine convention that only exists in C++ code.

Don't forget to put the #include "TutoProjectGameMode.h" line at the beginning of the TutoProjectHUD.cpp file, otherwise, the following error will appear when compiling:
error C2027: use of undefined type 'ATutoProjectGameMode'
pointer to incomplete class type is not allowed

If an error of this type appears related to any Unreal Engine class, access the Unreal Engine API Reference and search for the class. The documentation shows how to include the class header file. As an example, the image below shows some information about the UCanvas class.