Pages

quarta-feira, 5 de agosto de 2020

Creating the first function in C++

Let's create a function in C++ with the name StartGame(). A function name is always followed by parentheses. A function has one or more statements that will be executed when the function is called.

The StartGame() function is part of the TutoProjectGameMode class and is responsible for assigning the initial values of the game state variables that were created in the previous article. This function is called at the beginning of the game and after the end of the game if the player wants to play again.

A function declaration tells the compiler the name of the function, the parameters it receives, and the type of the return value. The function declaration is done in the header file (.h).

A function definition provides the body of the function containing the statements. The function definition is done in the implementation file (.cpp).

The StartGame() function will be public because it will also be used by the C++ class that represents the player when he wants to restart the game. We will place the declaration of this function in the file TutoProjectGameMode.h after the declaration of the constructor ATutoProjectGameMode(), as shown in the code below. Note that there is also the declaration of the BeginPlay() function. We will comment on BeginPlay() at the end of this article.
// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "TutoProjectGameMode.generated.h"

UCLASS(minimalapi)
class ATutoProjectGameMode : public AGameModeBase
{
	GENERATED_BODY()

public:
	ATutoProjectGameMode();

	void StartGame();

protected:
	int32 PlayerLevel;

	int32 Score;

	int32 ItemCount;

	int32 Time;

	bool  bGameOver;
    
	virtual void BeginPlay() override;
};
The void keyword that is before the StartGame() function name means that this function does not return a value. The empty parenthesis means that the function has no parameters. The parameters are used to pass values when the function is executed. As an example, if we wanted the function StartGame() to receive an integer value indicating the level of difficulty, the function declaration would look like this:

  void StartGame(int32 DifficultyLevel);
  
The DifficultyLevel parameter acts as a variable that can be used within the StartGame() function. This was just an example of a parameter, don't do this change to our game code.

The body of the StartGame() function containing the statements must be placed in the TutoProjectGameMode.cpp file. This file already has the body of the ATutoProjectGameMode() constructor that was created by the Third Person template.

The TutoProjectGameMode.cpp file will look like this:
// Copyright Epic Games, Inc. All Rights Reserved.

#include "TutoProjectGameMode.h"
#include "TutoProjectCharacter.h"
#include "UObject/ConstructorHelpers.h"

ATutoProjectGameMode::ATutoProjectGameMode()
{
 // set default pawn class to our Blueprinted character
 static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(
        TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter"));
 
 if (PlayerPawnBPClass.Class != NULL)
 {
  DefaultPawnClass = PlayerPawnBPClass.Class;
 }
}

void ATutoProjectGameMode::StartGame()
{
	Score = 0;
	PlayerLevel = 1;
	ItemCount = 0;
	Time = 30;
	bGameOver = false;
}

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

	StartGame();
}
Note that all function names are preceded by ATutoProjectGameMode::. The characters :: in C++ are the scope resolution operator. In this example, it is being used to indicate that the functions belong to the C++ class ATutoProjectGameMode.

ATutoProjectGameMode() is the class constructor. This function is executed when an instance of the ATutoProjectGameMode class is created in memory. Note that a constructor does not have a keyword defining the return type.

In this example, the constructor is looking for the class that represents the player to set as the DefaultPawnClass for this Game Mode. In a future article, we will examine these statements in detail.

Our StartGame() function is simple, it only assigns initial values to the variables. The = character is called an assignment operator in C++. In an assignment operation, the value to the right of the = operator is placed in the variable to the left of the operator. In the example below, the value 0 is placed in the Score variable. If the Score variable had a value previously, it will be lost.
Score = 0;

Now let's talk about the BeginPlay() function. If you have already programmed in Blueprints you should be familiar with the Event BeginPlay that is triggered when the game starts for an Actor.


The events in Unreal Engine are implemented in C++ using functions that do not return a value, that is, the return type is void. This is how we declared the BeginPlay() function:
virtual void BeginPlay() override;
The virtual keyword indicates functions that can be overridden in child classes. The BeginPlay() function was declared in the Unreal Engine C++ AActor class, so any class that belongs to the AActor hierarchy can override BeginPlay().

The word override is optional, but it is very useful. It is used to ensure that the programmer is actually overriding a function of the parent class. The programmer may confuse the number or type of parameters when overriding a function. Using override the compiler will generate an error if no equivalent function is found in the parent class.

In our example, the BeginPlay() function has only two statements. The first statement is Super::BeginPlay(); which is used to call the BeginPlay() function that was defined in the parent class, which in our example is the C++ AGameModeBase class. Unreal Engine has defined an identifier called Super to reference the parent class, which is also known as superclass. Child classes are also called subclasses.

The second statement is StartGame(); which is the call to the function we created to initialize the variables.