sexta-feira, 14 de agosto de 2020

Criando um Timer em Unreal C++

Um dos valores exibidos na tela é o da variável Time que armazena o tempo que está faltando para encerrar o jogo. Em outro artigo veremos como desenhar os valores das variáveis na tela.


A variável Time inicia com o valor 30. Precisamos de uma forma de diminuir 1 do valor desta variável a cada segundo. Para fazer isto vamos criar um Timer. Um Timer permite que uma função seja executada depois de passar o tempo especificado. Esta função pode ser executada uma única vez ou periodicamente.
 
Antes de criarmos um Timer, vamos precisar de uma variável do tipo FTimerHandle que será usada para referenciar o Timer que foi criado. Será necessário também criarmos uma função que será executada pelo Timer. A função se chamará Clock()

Abra o arquivo TutoProjectGameMode.h, coloque a variável TimerHandleClock e a declaração da função Clock() no bloco protected abaixo da função BeginPlay() conforme código abaixo. 
...
protected:
	int32 PlayerLevel;

	int32 Score;

	int32 ItemCount;

	int32 Time;

	bool  bGameOver;

	virtual void BeginPlay() override;

	FTimerHandle TimerHandleClock;

	void Clock();
};

Um jogo em execução possui um Timer Manager que pode ser acessado usando a função GetWorldTimerManager() em qualquer subclasse de AActor. O Timer Manager possui uma função chamada SetTimer() usada para criar um Timer.

Vamos colocar a criação do Timer dentro da função StartGame() que está no arquivo TutoProjectGameMode.cpp. A função StartGame() vai ficar com este conteúdo:
void ATutoProjectGameMode::StartGame()
{
  Score = 0;
  PlayerLevel = 1;
  ItemCount = 0;
  Time = 30;
  bGameOver = false;

  GetWorldTimerManager().SetTimer(TimerHandleClock, this, &ATutoProjectGameMode::Clock,
                                  1.0f, true);
}
A função SetTimer() está recebendo cinco parâmetros, vamos analisar a chamada da função e cada um dos parâmetros:
  • GetWorldTimerManager().SetTimer() : A primeira coisa que acontece nesta linha é a execução da função GetWorldTimerManager() que retorna uma instância do tipo FTimeManager.  Depois disso é executada a função SetTimer() da instância FTimeManager que foi retornada. 
  • TimerHandleClock Este é o primeiro parâmetro da função SetTimer()TimerHandleClock é a variável do tipo FTimerHandle que criamos. Ela será preenchida com as informações necessárias para posteriormente podermos referenciar o Timer que será criado.   
  • this : Esta é uma palavra chave do C++ que referencia a instância que está sendo executada neste momento. É semelhante a palavra Self usada em Blueprints.  
  • &ATutoProjectGameMode::Clock : Neste parâmetro informamos qual é a função que será executada pelo Timer. Observe que antes da identificação da função tem o operador &. Este operador é usado para retornar o endereço de memória da função. A identificação da função é composto pelo nome da classe, o operador de resolução de escopo :: e pelo nome da função sem parênteses.
  • 1.0f : Este parâmetro indica o tempo em segundos que o Timer deve esperar antes de executar a função. Este é um valor do tipo float. Vamos analisar o tipo float em outro artigo.
  • true : Este parâmetro booleano é o de Loop. Se for true então o Timer executará a função periodicamente. Se for false, a função será executada apenas uma vez.
 
A função SetTimer() é equivalente ao node Blueprint chamado Set Timer by Function Name que está na imagem abaixo. 


Falta apenas a definição da função Clock() para concluirmos o nosso Timer. Adicione o código abaixo no final do arquivo TutoProjectGameMode.cpp
void ATutoProjectGameMode::Clock()
{
  if (Time > 0)
  {
    Time--;
  } 
  else
  {
    bGameOver = true;
    GetWorldTimerManager().ClearTimer(TimerHandleClock);
  }
}
O Timer executa a função Clock() uma vez a cada segundo. Usamos o condicional if para testar se o valor da variável Time é maior que zero. Se for verdadeiro então a variável Time é decrementada, ou seja, o seu valor é diminuído de 1

Se o resultado da expressão do if for falso, então o bloco else será executado. No bloco else, a variável booleana bGameOver recebe o valor true para indicar que o jogo acabou. Depois é chamada a função ClearTime() para parar a execução do Timer que criamos.