quarta-feira, 5 de agosto de 2020

Criando a primeira função em C++

Vamos criar uma função em C++ com o nome StartGame(). O nome de uma função é sempre seguida de parênteses. Uma função possui um ou mais comandos que serão executados quando a função for chamada. 

A função StartGame() faz parte da classe TutoProjectGameMode e é responsável por atribuir os valores iniciais das variáveis de estado do jogo que foram criadas no artigo anterior. Esta função é chamada no início do jogo e após o fim do jogo, se o jogador quiser jogar de novo.

Uma declaração de função informa ao compilador o nome da função, os parâmetros que ela recebe e o tipo do valor de retorno. A declaração de função é feita no arquivo de cabeçalho (.h).

Uma definição de função fornece o corpo da função contendo os comandos. A definição de função é feita no arquivo de implementação (.cpp).

A função StartGame() será public porque ela também será usada pela classe C++ que representa o jogador quando ele quiser reiniciar o jogo. Vamos colocar a declaração desta função no arquivo TutoProjectGameMode.h depois da declaração do construtor ATutoProjectGameMode(), conforme o código abaixo. Observe que existe também a declaração da função BeginPlay(). Vamos comentar sobre BeginPlay() no fim deste artigo.
// 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;
};
A palavra chave void que está antes do nome da função StartGame() significa que esta função não retorna um valor. Os parênteses vazio significa que a função não possui parâmetros. Os parâmetros são usados para passar valores no momento da execução da função. Como exemplo, se quiséssemos que a função StartGame() recebesse um valor inteiro indicando o nível de dificuldade, a declaração da função ficaria assim:

  void StartGame(int32 DifficultyLevel);
  
O parâmetro DifficultyLevel funciona como uma variável que pode ser usado dentro da função StartGame(). Isto foi apenas um exemplo de parâmetro, não faça esta mudança no código do nosso jogo.

O corpo da função StartGame() contendo os comandos deve ser colocado no arquivo TutoProjectGameMode.cpp. Este arquivo já possui o corpo do construtor ATutoProjectGameMode() que foi criado pelo modelo do projeto Third Person.

O arquivo TutoProjectGameMode.cpp fica assim:
// 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();
}
Observe que todos os nomes das funções estão precedidos por ATutoProjectGameMode::. Os caracteres :: em C++ é o operador de resolução de escopo. Neste exemplo ele está sendo usado para indicar que as funções pertencem à classe C++ ATutoProjectGameMode

ATutoProjectGameMode() é o construtor da classe. Esta função é executada no momento que uma instância da classe ATutoProjectGameMode é criada na memória. Observe que um construtor não possui uma palavra chave definindo o tipo de retorno.

Neste exemplo, o construtor está buscando a classe que representa o jogador para definir como o DefaultPawnClass deste Game Mode. Em um artigo futuro vamos examinar em detalhes estes comandos. 

A nossa função StartGame() é simples, ela apenas atribui valores iniciais para as variáveis. O caractere = é chamado de operador de atribuição em C++. Em uma operação de atribuição, o valor que está à direita do operador = é colocado na variável à esquerda do operador. No exemplo abaixo, o valor 0 é colocado na variável Score. Se a variável Score possuía um valor anteriormente, ele será perdido.
Score = 0;

Agora vamos falar sobre a função BeginPlay(). Se você já programou em Blueprints deve estar familiarizado com o Evento BeginPlay que é acionado quando o jogo começa para um Actor


Os eventos na Unreal Engine são implementados em C++ usando funções que não retornam valor, ou seja o tipo de retorno é void. Esta foi a forma que declaramos a função BeginPlay():
virtual void BeginPlay() override;
A palavra chave virtual indica funções que podem ser sobrescritas em classes filhas. A função BeginPlay() foi declarada na classe C++ AActor da Unreal Engine, sendo assim qualquer classe que pertence à hierarquia de AActor pode sobrescrever BeginPlay().

A palavra override é opcional, mas é muito útil. Ela é usada para garantir que o programador realmente está sobrescrevendo uma função da classe pai. O programador pode confundir o número ou tipo de parâmetros ao sobrescrever uma função. Usando override o compilador irá gerar um erro caso não seja encontrada uma função na classe pai que seja equivalente.   

Em nosso exemplo, a função BeginPlay() só possui dois comandos. O primeiro comando é Super::BeginPlay(); que é usado para chamar a função BeginPlay() que foi definida na classe pai, que em nosso exemplo é a classe C++ AGameModeBase. A Unreal Engine definiu um identificador chamado Super para referenciar a classe pai, que também é conhecida por superclasse. As classes filhas também são chamadas de subclasses.

O segundo comando é o StartGame(); que é a chamada para a função que criamos para inicializar as variáveis.