Neste artigo vamos converter uma parte do script do Blueprint FirstPersonCharacter (renomeado para BP_PlayerCharacter).
Existem dois fatores importantes que devem ser levados em consideração para decidir se um script Blueprint deve ser convertido para C++:
- Complexidade: Algumas vezes é necessário implementar uma lógica complexa ou que envolva muitos cálculos matemáticos. Devido a natureza visual do Blueprint, estes tipos de script podem se tornar confusos ao serem representados por nodes Blueprint, sendo mais adequado e legível a implementação em C++.
- Velocidade: A velocidade de execução de um código C++ é mais rápida do que de um script Blueprint. Isto não significa que você deva converter todos os seus Blueprints para C++ só por este motivo. Existem inúmeros outros fatores que vão definir o desempenho de um projeto Unreal. O que você precisa verificar é se existem scripts não triviais que são executados com muita frequência, por exemplo, nodes Blueprint que estejam ligados ao evento Tick.
Iremos converter para C++ um script Blueprint simples para mostrar como isto é feito. Abra o Blueprint BP_PlayerCharacter e veja no Event Graph as ações que estão em Movement Input. Eu removi os nodes relacionados ao teste de uso de HMD (Head Mount Display) para manter o exemplo simples como mostra a imagem abaixo.
Vamos pegar os Nodes Blueprint do evento InputAxis MoveForward e convertê-los para uma única função C++. Neste exemplo são apenas dois nodes, mas se fossem dezenas de nodes, eles também poderiam ser convertidos em uma única função C++. Faremos a mesma conversão para o evento InputAxis MoveRight.
Precisamos encontrar as funções C++ equivalentes aos nodes Blueprint. Abaixo do nome de um node Blueprint tem a linha Target is ..., que indica a classe onde foi definida a função representada pelo node. Na imagem acima temos dois nodes cujo Target é Actor e dois nodes com Target Pawn. Todas essas funções serão acessíveis na nossa classe C++ PlayerCharacter, porque a classe Character herda as variáveis e funções da classe Pawn e a classe Pawn herda as variáveis e funções da classe Actor.
O primeiro passo é pesquisar a função na Unreal Engine API Reference. Procure pelo nome do node Blueprint removendo os espaços em brancos, por exemplo, AddMovementInput. Na API Reference você pode ver a descrição dos parâmetros da função. Infelizmente, a API Reference não indica se o parâmetro é opcional. Para verificarmos isso, olhe na página da função na API Reference o caminho e nome do arquivo Header. Procure pelo arquivo na pasta Engine do seu projeto no Visual Studio. Abra o arquivo e procure pelo nome da função dentro do arquivo. A declaração da função AddMovementInput é feita desta forma:
UFUNCTION(BlueprintCallable, Category="Pawn|Input", meta=(Keywords="AddInput"))
virtual void AddMovementInput(FVector WorldDirection, float ScaleValue = 1.0f,
bool bForce = false);
Observe que os parâmetros ScaleValue e bForce estão recebendo valores padrões. Isto significa que estes parâmetros são opcionais e a função AddMovementInput pode ser chamada passando apenas o parâmetro WorldDirection.
No artigo anterior criamos a classe C++ PlayerCharacter para ser usada como classe pai do Blueprint BP_PlayerCharacter. Abra o arquivo PlayerCharacter.h e adicione as declarações das novas funções MoveForward() e MoveRight() como mostra o código abaixo.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "PlayerCharacter.generated.h"
UCLASS()
class TUTOPART3_API APlayerCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
APlayerCharacter();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
override;
UFUNCTION(BlueprintCallable, Category = Movement)
void MoveForward(float Value);
UFUNCTION(BlueprintCallable, Category = Movement)
void MoveRight(float Value);
};
No arquivo PlayerCharacter.cpp temos a implementação das funções MoveForward() e MoveRight() usando a mesma lógica que estava no script Blueprint.
#include "PlayerCharacter.h"
// Sets default values
APlayerCharacter::APlayerCharacter()
{
// Set this character to call Tick() every frame.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void APlayerCharacter::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void APlayerCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
void APlayerCharacter::MoveForward(float Value)
{
AddMovementInput(GetActorForwardVector(), Value);
}
void APlayerCharacter::MoveRight(float Value)
{
AddMovementInput(GetActorRightVector(), Value);
}
O primeiro parâmetro da função AddMovementInput() recebe o valor de retorno da função que está sendo chamada.
Só uma observação em relação ao parâmetro Value usado nas funções de movimento. Se Value for negativo, o movimento será na direção oposta.
Compile o código C++.
Abra o Blueprint BP_PlayerCharacter. Vamos susbtituir no Event Graph os nodes Blueprint que estão em Movement Input pela nossas funções C++. Mantenha os nodes de evento InputAxis e remova os outros.
Clique com o botão direito no Event Graph do Blueprint, procure as nossas funções C++ no Menu de Contexto, na categoria Movement e adicione-as ao Event Graph que deve ficar assim:
Veja que o Target dos nodes Blueprint é Player Character.
Foi feito este exemplo simples para que você possa entender este processo de conversão.