quarta-feira, 4 de novembro de 2020

A classe UObject

A classe UObject é a classe base para todos objetos da Unreal Engine. Ela fornece um conjunto de serviços importantes como reflexão, serialização, networking e gerenciamento de memória.

Instâncias de UObject não podem ser adicionadas no nível. Elas devem fazer parte de um Actor. Se você quer criar uma classe que possa ser instanciada no nível, ela tem de herdar de AActor.

As classes que herdam de UObject mas não herdam de AActor tem o prefixo U. Como exemplo temos a classe UActorComponent que representa os componentes que são adicionados em um Actor.

Para criar uma instância de uma subclasse de UObject utilize a função NewObject().  A linha abaixo mostra um exemplo, assumindo que a classe UObjectChild é uma subclasse de UObject:

UObjectChild* ObjectChild = NewObject<UObjectChild>(this,UObjectChild::StaticClass());

A Unreal Engine irá gerenciar a memória deste objeto e destruí-lo quando não for mais necessário. Mas se você quiser destruir uma instância de UObject, pode usar a função ConditionalBeginDestroy() e anular o ponteiro:

ObjectChild->ConditionalBeginDestroy();
ObjectChild = nullptr;


Exemplo de uso:

Crie uma classe C++ com o nome RpgDiceSet usando como classe pai a classe Object. É preciso marcar a opção Show All Classes para que a class Object seja listada como mostra a imagem.



A classe RpgDiceSet vai representar um conjunto de cinco dados. Ela possui a função RollDice() para rolar os dados e a função ResultString() que retorna o resultado dos dados.

No arquivo RpgDiceSet.h, adicione o seguinte código:

...

UCLASS()
class TUTOPROJECT_API URpgDiceSet : public UObject
{
  GENERATED_BODY()

//Por simplicidade, as variávéis estão públicas.	
public: 
	
  //Die (dado) é o singular de Dice (dados)	
  int32 Die1;
  int32 Die2;
  int32 Die3;
  int32 Die4;
  int32 Die5;
  
  void RollDice(int32 NumFaces);

  FString ResultString();
	
}; 

No arquivo RpgDiceSet.cpp, adicione a implementação das duas funções mostradas abaixo:

#include "RpgDiceSet.h"

void URpgDiceSet::RollDice(int32 NumFaces)
{  
  if(NumFaces >= 2 && NumFaces <= 20)
  {
    Die1 = FMath::RandRange(1, NumFaces);
    Die2 = FMath::RandRange(1, NumFaces);
    Die3 = FMath::RandRange(1, NumFaces);
    Die4 = FMath::RandRange(1, NumFaces);
    Die5 = FMath::RandRange(1, NumFaces);
  }
  else
  {
    Die1 = 0;
    Die2 = 0;
    Die3 = 0;
    Die4 = 0;
    Die5 = 0;	
  }
}
  
FString URpgDiceSet::ResultString()
{
	  
  FString Result = FString::Printf(
                      TEXT("Die 1: %d; Die 2: %d; Die 3: %d; Die 4: %d; Die 5: %d;"), 
                      Die1, Die2, Die3, Die4, Die5);
									 
  return Result;
									 
}

A função RollDice() tem o parâmetro NumFaces que indica o número de faces dos dados. Deve ser passado um valor inteiro entre 2 e 20. A função FMath::RandRange(int32 Min, int32 Max) retorna um valor inteiro aleatório >= Min e <= Max.

A função ResultString() retorna um FString contendo os resultados de todos os dados. 

Agora crie uma classe C++ com o nome TestUObject usando como classe pai a classe Actor. No arquivo TestUObject.cpp, adicione o #include "RpgDiceSet.h" e implemente a função BeginPlay() desta forma:

#include "TestUObject.h"
#include "RpgDiceSet.h"

void ATestUObject::BeginPlay()
{
  Super::BeginPlay();
	
  URpgDiceSet* RpgDiceSet = NewObject<URpgDiceSet>(this, URpgDiceSet::StaticClass());

  RpgDiceSet->RollDice(20);
	
  if(GEngine)
  {
    GEngine->AddOnScreenDebugMessage(-1, 10, FColor::Red, 
                                     RpgDiceSet->ResultString() );
  }

  RpgDiceSet->ConditionalBeginDestroy();
  RpgDiceSet = nullptr;	
}

...

A função BeginPlay() cria uma instância da classe URpgDiceSet, chama as suas funções, mostra o resultado na tela e depois inicia a destruição da instância que foi criada.

Compile o código C++ e adicione uma instância de TestUObject no nível. Inicie o jogo e veja os resultados dos dados sendo exibidos na tela. A imagem abaixo mostra uma das execuções:



Sumário C++