sexta-feira, 23 de outubro de 2020

A macro UPROPERTY()

A macro UPROPERTY() é usada para expor variáveis para o editor da Unreal Engine e para incluir a propriedade no sistema de gerenciamento de memória da Unreal Engine.

macro UPROPERTY() é colocada na linha acima da definição da variável C++ como mostra o exemplo abaixo:

UPROPERTY(EditAnywhere, Category = Tutorial)
int32 SpecialId;

Os parâmetros de UPROPERTY() são chamados de especificadores de propriedades. No exemplo acima foi usado o EditAnywhere e o  Category que é usado para agrupar as variáveis na janela de propriedades. O uso de aspas é opcional no nome de Category, mas necessário se o nome de Category tiver um espaço em branco.

Vamos analisar um grupo de seis especificadores de propriedades. Uma propriedade só pode usar um especificador desse grupo de seis que está listado abaixo. Esses seis especificadores são a combinação de duas informações. A primeira informação é se a propriedade é somente leitura (Visible) ou editável (Edit). A segunda informação é relacionado ao local que a propriedade aparece e pode ser apenas em instâncias (InstanceOnly), apenas no editor de Blueprints (DefaultsOnly) ou nos dois (Anywhere).

Os seis especificadores são esses:

  • VisibleInstanceOnly: Somente leitura, aparece na janela de propriedades das instâncias.
  • VisibleDefaultsOnlySomente leitura, aparece na janela de propriedades do editor de Blueprints. 
  • VisibleAnywhere: Somente leitura, aparece na janela de propriedades das instâncias e do editor de Blueprints. 
  • EditInstanceOnlyEditável, aparece na janela de propriedades das instâncias.
  • EditDefaultsOnlyEditável, aparece na janela de propriedades do editor de Blueprints.
  • EditAnywhereEditável, aparece na janela de propriedades das instâncias e do editor de Blueprints.


Os ponteiros para componentes geralmente possuem o especificador VisibleAnywhere. Isto evita que o ponteiro seja alterado, mas as propriedades do componente podem ser modificadas.
 
Os dois especificadores abaixo indicam como a propriedade será usada no Event Graph de um Blueprint. Se nenhum dos dois especificadores estiverem presentes, a propriedade não é listada para uso no Event Graph.
  • BlueprintReadOnly: Pode ser lida mas não pode ser modificada no Event Graph.
  • BlueprintReadWritePode ser lida e modificada no Event Graph.

Existe outro tipo de especificador conhecido como Metadata. Esses são alguns exemplos:
  • DisplayName="Property Name": Nome que será exibido nas janelas de propriedades.
  • ClampMin="N": Valor mínimo que pode ser inserido para uma propriedade. Pode ser usado em propriedades do tipo inteiro e float.
  • ClampMax="N": Valor máximo que pode ser inserido para uma propriedade. Pode ser usado em propriedades do tipo inteiro e float. 

Para usar um especificador Metadata, utilize a palavra meta e coloque os especificadores dentro dos parênteses como mostrado abaixo: 
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Tutorial, 
          meta=(DisplayName="Special Identification", ClampMin="0", ClampMax="999") )
int32 SpecialId;


Exemplo de uso:

Crie uma classe C++ com o nome TestUProperty usando como classe pai a classe Actor. No arquivo TestUProperty.h, adicione a definição de três variáveis como mostra o código abaixo:

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TestUProperty.generated.h"

UCLASS()
class TUTOPROJECT_API ATestUProperty : public AActor
{
  GENERATED_BODY()
	
public:	
  // Sets default values for this actor's properties
  ATestUProperty();
	
  UPROPERTY(EditInstanceOnly, Category = Tutorial)
  FString NPCName;
	
  UPROPERTY(VisibleDefaultsOnly, Category = Tutorial)
  float BaseClassVersion;
	
  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Tutorial,
            meta=(DisplayName="Special Identification", ClampMin="0", ClampMax="999") )
  int32 SpecialId;

...


No arquivo TestUProperty.cpp atribua um valor inicial para a variável BaseClassVersion dentro do construtor:
#include "TestUProperty.h"

ATestUProperty::ATestUProperty()
{
  // Set this actor to call Tick() every frame.
  PrimaryActorTick.bCanEverTick = true;

  BaseClassVersion = 0.3f;
}

...


Compile o código e adicione uma instância de TestUProperty no nível. Você não conseguirá mover a instância no nível porque não definimos um RootComponent para ela. Mas você consegue selecionar a instância usando o World Outliner.

Veja na aba Details que as propriedades NPCName e Special Id aparecem e são editáveis, mas a variável BaseClassVersion não aparece porque o especificador VisibleDefaultsOnly indica que ela só deve aparecer no editor de Blueprints.


Special Identification é o nome que foi atribuido à variável SpecialId usando o especificador DisplayName. Os especificadores ClampMin e ClampMax definem a faixa de valores possíveis para SpecialId. Se você colocar um valor maior que 999 o editor automaticamente muda para 999.

Agora vamos criar um Blueprint baseado na classe C++ TestUProperty para vermos a variável BaseClassVersionNavegue até a pasta das classes C++ usando o Content Browser do editor e clique com o botão direito na classe TestUProperty. Escolha a opção Create Blueprint class based on TestUProperty.


Abra o novo Blueprint e clique no botão Class Defaults. Veja que a variável BaseClassVersion aparece mas não está editável e a variável NPCName não aparece, porque ela só deve aparecer nas instâncias.


Clique com o botão direito no EventGraph do Blueprint e pesquise usando a palavra "special". Veja que aparecem as funções Get e Set para a variável SpecialId. Isto é devido o especificador BlueprintReadWrite. As outras duas variáveis não aparecem na lista de Ações.


A listagem de Ações do Blueprint usou o nome que estava no especificador DisplayName da variável SpecialId, mas os nodes do Blueprint usaram o nome da variável como está no código. 


Sumário C++