terça-feira, 18 de agosto de 2020

Classe TutoProjectHUD: Usando ponteiros C++

Neste artigo vamos criar a classe TutoProjectHUD que é responsável por desenhar na tela as variáveis de estado do jogo. Entretanto, essas variáveis pertencem à classe TutoProjectGameMode. Vamos precisar usar um ponteiro para ter acesso às variáveis e funções públicas da classe TutoProjectGameMode dentro da classe TutoProjectHUD.

Primeiro, vamos criar a classe TutoProjectHUD. No Content Browser, acesse a pasta TutoProject que está dentro da pasta C++ Classes. Clique com o botão direito em um espaço livre e escolha a opção New C++ Class... como mostra a imagem abaixo.


Na tela seguinte você tem de escolher a classe pai que será usada como tipo para a nova classe. Role as opções até encontrar a classe HUD. Selecione a classe HUD e clique no botão Next.  


No campo Name coloque TutoProjectHUD. No campo Path, mantenha a pasta padrão do projeto. Clique no botão Create Class


Neste artigo vamos focar apenas em como criar um ponteiro para a classe TutoProjectGameMode e como obter a referência para o Game Mode que está sendo usado pelo jogo. Em outro artigo vamos ver as funções usadas para desenhar na tela.

Um ponteiro armazena um endereço de memória. Podemos usar um ponteiro para referenciar uma instância de uma classe. Você define que uma variável é um ponteiro usando o operador * ao lado do tipo da variável. A linha de código abaixo mostra a definição de uma variável chamada TutoProjectGameMode que é um ponteiro para uma instância da classe ATutoProjectGameMode.  
ATutoProjectGameMode* TutoProjectGameMode;
A linha acima definiu um ponteiro mas ele ainda não está armazenando uma referência de uma instância da classe ATutoProjectGameMode. Na função BeginPlay(), nós vamos obter uma referência para a instância da classe ATutoProjectGameMode que está sendo usada pelo jogo e armazenar em nosso ponteiro.

Abra o arquivo TutoProjectHUD.h, acrescente o rótulo protected: e as declarações do ponteiro TutoProjectGameMode e da função BeginPlay() como mostra o código abaixo. 
#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;
		
};
Observe que existe a palavra chave class antes da definição do ponteiro TutoProjectGameMode. Isto foi necessário porque a classe ATutoProjectHUD não conhece a classe ATutoProjectGameMode. É uma maneira de informar ao compilador que existe uma classe chamada ATutoProjectGameMode e que a definição da classe será encontrada posteriormente durante a compilação. Isto é conhecido como Forward Declaration.

Ao invés de usar a palavra chave class, você poderia adicionar um #include "TutoProjectGameMode.h" no início do arquivo, pois este arquivo de cabeçalho contém a definição da classe ATutoProjectGameMode. Mas, sempre que possível, evite adicionar mais #include em arquivos de cabeçalho (.h). É melhor colocá-los nos arquivos de implementação (.cpp).

O arquivo TutoProjectHUD.cpp tem de ter este conteúdo:
#include "TutoProjectHUD.h"
#include "TutoProjectGameMode.h"

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

  TutoProjectGameMode = GetWorld()->GetAuthGameMode<ATutoProjectGameMode>();
}
Vamos analisar a linha responsável por obter e armazenar a referência para o Game Mode em nosso ponteiro:
  • TutoProjectGameMode : Esta é a nossa variável ponteiro.
  • GetWorld() : Esta função retorna um ponteiro para uma instância da classe UWorld que representa o mapa atual.
  • -> : Quando o você tem um ponteiro, é preciso usar o operador -> para acessar as funções e variáveis de uma instância.
  • GetAuthGameMode<ATutoProjectGameMode>() : Esta função retorna um ponteiro para a instância do Game Mode que está sendo usado pelo mapa. A função usa um parâmetro de template do C++, que é a classe que está sendo informada entre < >

A função GetAuthGameMode tentará fazer o Cast do Game Mode para a classe ATutoProjectGameMode. Cast é uma conversão de tipos. Esta conversão só vai funcionar se o mapa estiver usando o Game Mode TutoProjectGameMode. Se você não é familiarizado com o Game Mode, veja o link abaixo:

A próximo imagem mostra como seria o conteúdo desta função/evento BeginPlay() se ela tivesse sido feita em Blueprints.


Por propósito didático, eu coloquei o nome da classe usada no node Cast como ATutoProjectGameMode para facilitar a associação com o código C++. Mas lembre-se que o prefixo A é uma convenção da Unreal Engine que só existe no código C++.

Não esqueça de colocar a linha #include "TutoProjectGameMode.h" no início do arquivo TutoProjectHUD.cpp, senão irá aparecer o seguinte erro no momento da compilação:
error C2027: use of undefined type 'ATutoProjectGameMode'
pointer to incomplete class type is not allowed

Se aparecer um erro deste tipo relacionado a alguma classe da Unreal Engine, acesse a Unreal Engine API Reference e procure pela classe. A documentação mostra como fazer o include do arquivo cabeçalho da classe. Como exemplo, a imagem abaixo mostra alguns dados da classe UCanvas