Learning C++ in Unreal Engine: Basic Syntax & Concepts

Julien Hora
tokyopixels
7 min readMay 22, 2024

--

Now that you have a good grasp of the Unreal Engine project structure, it’s time to dive into the basics of C++ syntax and concepts. This article will introduce you to the fundamental elements of C++ programming, tailored specifically for Unreal Engine development.

Variables and Data Types

Variables are the building blocks of any programming language. They store data that your game can manipulate.

Declaring Variables

When declaring variables in C++, you specify the type of data the variable will hold, followed by the variable name. In the example above, int declares an integer variable named Health, float declares a floating-point variable named Speed, and bool declares a boolean variable named bIsAlive. Declaring a variable sets aside memory for it, but the initial value is undefined until it is initialized.

int Health;
float Speed;
bool bIsAlive;

Initializing Variables

Initializing variables means assigning them an initial value at the time of declaration. This is done by using the assignment operator (=) followed by the value you want to assign. For instance, int Health = 100; declares an integer variable Health and initializes it with the value 100. Proper initialization ensures that your variables have defined and predictable values when your game starts executing.

int Health = 100;
float Speed = 600.0f;
bool bIsAlive = true;

Common Data Types

Understanding the various data types available in C++ is crucial for effective programming. Different data types allow you to store and manipulate different kinds of data in your game.

  • int: This data type is used to store integer values, which are whole numbers without decimal points. For example, int Score = 100; stores the integer value 100 in the variable Score.
  • float: This data type is used to store floating-point numbers, which are numbers that can have decimal points. For example, float Speed = 600.0f; stores the floating-point value 600.0 in the variable Speed. The f at the end of the value indicates that it's a float literal.
  • bool: This data type is used to store boolean values, which can either be true or false. For example, bool bIsAlive = true; stores the boolean value true in the variable bIsAlive. Boolean values are often used in conditional statements to control the flow of the game.
  • FString: This is a string data type specific to Unreal Engine, used to store sequences of characters. For example, FString PlayerName = TEXT("Player1"); stores the string "Player1" in the variable PlayerName. The TEXT macro is used to ensure compatibility across different platforms.

There are plenty of data types and you will also soon start creating your own, but these 4 are the basics for what is to come next.

Functions and Methods

Functions (or methods when they belong to a class) are blocks of code that perform specific tasks.

Defining a Function

Defining a function involves specifying the function’s return type, name, and parameters (if any). In this example, void indicates that the function does not return any value. PrintHealth is the function's name, and the code within the curly braces {} is the function's body, which contains the logic to be executed when the function is called. Here, the function uses UE_LOG to print the player's health to the output log.

void PrintHealth()
{
UE_LOG(LogTemp, Warning, TEXT("Player Health: %d"), Health);
}

Calling a Function

Calling a function is straightforward: you simply write the function’s name followed by parentheses. In this example, PrintHealth(); calls the PrintHealth function, executing the code within its body. Calling functions allows you to execute the same block of code from different parts of your game, promoting code reuse and modularity.

PrintHealth();

Function Parameters and Return Types

Functions can take parameters, which are inputs that the function can use to perform its task. In the example above, CalculateDamage takes two parameters: an integer BaseDamage and a floating-point Modifier. The function returns an integer result, as indicated by the int return type. By passing different arguments to the function, you can perform calculations or operations with varying inputs. The return type specifies the type of value the function will return to the caller.

int CalculateDamage(int BaseDamage, float Modifier)
{
return BaseDamage * Modifier;
}

int Damage = CalculateDamage(50, 1.5f);

Classes and Objects

C++ is an object-oriented language, which means it uses classes and objects to organize code.

Defining a Class

A class definition in C++ starts with the class keyword followed by the class name. In Unreal Engine, the UCLASS() macro is used to integrate the class with the engine's reflection system, enabling features like Blueprint integration and property editing in the editor. The GENERATED_BODY() macro is required for all Unreal Engine classes to handle boilerplate code. Within the class, you define member variables and functions. In the example, Health is a member variable with properties allowing it to be edited in Blueprints and the editor. The TakeDamage function can be called from Blueprints.

UCLASS()
class AMyCharacter : public ACharacter
{
GENERATED_BODY()

public:
// Constructor
AMyCharacter();

// Member variables
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
int Health;

// Member functions
UFUNCTION(BlueprintCallable, Category = "Actions")
void TakeDamage(int DamageAmount);
};

Constructor and Member Functions

A constructor is a special function that is called when an object of the class is created. It typically initializes member variables. In the example, the AMyCharacter constructor sets the Health variable to 100. Member functions, such as TakeDamage, define the behaviors of the class. This function decreases the Health variable by the specified DamageAmount and logs the updated health value. Constructors and member functions encapsulate the data and behavior associated with objects of the class.

AMyCharacter::AMyCharacter()
{
// Initialize variables
Health = 100;
}

void AMyCharacter::TakeDamage(int DamageAmount)
{
Health -= DamageAmount;
UE_LOG(LogTemp, Warning, TEXT("Health now: %d"), Health);
}

Control Flow

Control flow statements dictate the order in which code executes, allowing you to implement decision-making, loops, and conditional logic in your game.

If Statements

If statements allow your game to execute specific blocks of code based on certain conditions. In this example, the if statement checks if the Health variable is less than or equal to 0. If this condition is true, the code inside the curly braces {} runs, setting bIsAlive to false and logging that the character is dead. If statements are fundamental for implementing game logic, such as responding to player actions or changes in game state.

if (Health <= 0)
{
bIsAlive = false;
UE_LOG(LogTemp, Warning, TEXT("Character is dead"));
}
else
{
bIsAlive = true;
UE_LOG(LogTemp, Warning, TEXT("Character is still alive"));
}

For Loops

For loops are used to repeat a block of code a specific number of times. In this example, the loop runs 10 times, with the variable i starting at 0 and increasing by 1 with each iteration until it reaches 10. Inside the loop, the current value of i is logged. For loops are useful for tasks that require iteration, such as processing arrays, spawning multiple objects, or performing repeated actions.

for (int i = 0; i < 10; i++)
{
UE_LOG(LogTemp, Warning, TEXT("Loop iteration: %d"), i);
}

While Loops

While loops repeat a block of code as long as a specified condition remains true. In this example, the loop continues to execute as long as Health is greater than 0. Each iteration decreases Health by 10 and logs the new value. While loops are ideal for scenarios where the number of iterations is not known beforehand and depends on dynamic conditions, such as waiting for an event to occur or processing input until a condition is met.

while (Health > 0)
{
Health -= 10;
UE_LOG(LogTemp, Warning, TEXT("Health: %d"), Health);
}

Understanding Pointers and References

Pointers and references are crucial concepts in C++ that allow you to manage memory and pass data efficiently.

Pointers

Pointers are variables that store memory addresses, allowing you to directly access and manipulate data stored in those addresses. In this example, HealthPointer is declared as a pointer to an integer and initialized with the address of the Health variable using the address-of operator (&). Pointers are essential for dynamic memory allocation, creating complex data structures like linked lists and trees, and interfacing with low-level system functions. Understanding how to use pointers effectively can lead to more efficient and flexible code.

UCameraComponent* CameraPointer = &Camera;

Dereferencing Pointers

Dereferencing a pointer means accessing the value stored at the memory address the pointer is pointing to. In this example, *HealthPointer retrieves the value stored at the address contained in HealthPointer and assigns it to HealthValue. The asterisk (*) operator is used for dereferencing. Dereferencing pointers is crucial when you need to read or modify the value of a variable indirectly, providing a powerful way to interact with memory and pass data between functions without copying.

int HealthValue = *HealthPointer;

References

References are alternative names for existing variables, allowing you to access and modify the original variable directly. In this example, HealthRef is a reference to the Health variable. Any changes made to HealthRef directly affect Health. References are often used in function parameters to avoid copying large data structures, improve performance, and ensure that modifications within a function affect the original variable. Unlike pointers, references cannot be null and must be initialized when declared.

int& HealthRef = Health;
HealthRef = 50;

Conclusion

This article introduced you to the basics of C++ syntax and concepts, focusing on variables, functions, classes, control flow, and pointers. These fundamentals are essential for developing games in Unreal Engine.

In the next article, we’ll explore how to create and use C++ classes in Unreal Engine, including the use of important macros like UCLASS, UPROPERTY, and UFUNCTION. This knowledge will allow you to start building the core functionality of your game.

Stay tuned and happy coding!

--

--

Julien Hora
tokyopixels

Founder @ Dreamrunner Labs | Senior Software Engineer | Unreal Engine Generalist