Neste artigo vamos criar uma subclasse de AActor contendo diversos componentes para mostrar na prática como eles são usados em C++.
Estes são os componentes que serão usados no exemplo:
- Scene Component: É usado como o Root Component do Actor.
- Static Mesh Component: Contém um Static Mesh que representa visualmente o Actor.
- Capsule Component: Componente usado para o teste de colisão.
- Particle System Component: Contém um emissor de partículas.
- Point Light Component: Componente que emite luz em todas as direções a partir de um ponto.
- Rotating Movement Component: Usado para rotacionar constantemente o Actor.
- Audio Component: Usado para executar som no local onde está o Actor.
Exemplo de uso:
Para este exemplo será necessário um projeto com o Starter Content.
Vamos criar uma cadeira elétrica. Toda a sua funcionalidade será feita através de componentes. Ela terá um emissor de partículas simulando as faíscas e um componente de áudio com o som das faíscas. Ela conterá um ponto de luz vermelho e ficará em rotação constante.
Crie uma classe C++ com o nome ElectricChair usando como classe pai a classe Actor. No arquivo ElectricChair.h faça a definição de todos os componentes e declare a função PostInitializeComponents(), como mostra o código abaixo:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ElectricChair.generated.h"
UCLASS()
class TUTOPROJECT_API AElectricChair : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AElectricChair();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
virtual void PostInitializeComponents() override;
UPROPERTY(VisibleAnywhere)
USceneComponent* RootScene;
UPROPERTY(VisibleAnywhere)
UStaticMeshComponent* StaticMeshComponent;
UPROPERTY(VisibleAnywhere)
class UCapsuleComponent* CapsuleComponent;
UPROPERTY(VisibleAnywhere)
class UParticleSystemComponent* ParticleSystemComponent;
UPROPERTY(VisibleAnywhere)
class UPointLightComponent* PointLightComponent;
UPROPERTY(VisibleAnywhere)
class URotatingMovementComponent* RotatingMovementComponent;
UPROPERTY(VisibleAnywhere)
class UAudioComponent* AudioComponent;
UPROPERTY(VisibleAnywhere, Category = Sound)
class USoundCue* SparksSoundCue;
};
No arquivo cpp temos de adicionar as linhas #include com os arquivos header das classes dos componentes. Para saber como fazer o #include de uma classe, procure pela classe na Unreal Engine API Reference.
No construtor da classe são carregados os Assets de Static Mesh, Particle System e SoundCue. Para obter o caminho de um Asset no editor da Unreal, clique com o botão direito no Asset e escolha a opção Copy Reference.
O construtor contém as inicializações dos componentes. O arquivo ElectricChair.cpp deve ter este conteúdo:
#include "ElectricChair.h"
#include "Engine/CollisionProfile.h"
#include "Components/CapsuleComponent.h"
#include "Components/PointLightComponent.h"
#include "Components/AudioComponent.h"
#include "Particles/ParticleSystemComponent.h"
#include "GameFramework/RotatingMovementComponent.h"
#include "Sound/SoundCue.h"
#include "Engine/EngineTypes.h"
// Sets default values
AElectricChair::AElectricChair()
{
// Set this actor to call Tick() every frame.
PrimaryActorTick.bCanEverTick = true;
// RootComponent initialization
RootScene = CreateDefaultSubobject<USceneComponent>(TEXT("RootScene"));
RootComponent = RootScene;
// CapsuleComponent initialization
CapsuleComponent = CreateDefaultSubobject<UCapsuleComponent>(
TEXT("CapsuleComponent"));
CapsuleComponent->InitCapsuleSize(44.f, 60.f);
CapsuleComponent->SetCollisionProfileName(
UCollisionProfile::BlockAllDynamic_ProfileName);
CapsuleComponent->SetupAttachment(RootScene);
CapsuleComponent->SetRelativeLocation(FVector(0.f, 0.f, 60.f));
// StaticMeshComponent initialization
StaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(
TEXT("StaticMeshComponent"));
StaticMeshComponent->SetCollisionProfileName(
UCollisionProfile::NoCollision_ProfileName);
StaticMeshComponent->SetMobility(EComponentMobility::Movable);
StaticMeshComponent->SetupAttachment(RootScene);
ConstructorHelpers::FObjectFinder<UStaticMesh> MeshFile(
TEXT("/Game/StarterContent/Props/SM_Chair.SM_Chair"));
if (MeshFile.Succeeded())
{
StaticMeshComponent->SetStaticMesh(MeshFile.Object);
}
// AudioComponent initialization
AudioComponent = CreateDefaultSubobject<UAudioComponent>(TEXT("AudioComponent"));
AudioComponent->SetupAttachment(RootScene);
ConstructorHelpers::FObjectFinder<USoundCue> SoundCueFile(
TEXT("/Game/StarterContent/Audio/Fire_Sparks01_Cue.Fire_Sparks01_Cue"));
if (SoundCueFile.Succeeded())
{
SparksSoundCue = SoundCueFile.Object;
}
// ParticleSystemComponent initialization
ParticleSystemComponent = CreateDefaultSubobject<UParticleSystemComponent>(
TEXT("ParticleSystemComponent"));
ConstructorHelpers::FObjectFinder<UParticleSystem> ParticleTemplate(
TEXT("/Game/StarterContent/Particles/P_Sparks.P_Sparks"));
if (ParticleTemplate.Succeeded())
{
ParticleSystemComponent->SetTemplate(ParticleTemplate.Object);
}
ParticleSystemComponent->SetAutoActivate(true);
ParticleSystemComponent->SetupAttachment(StaticMeshComponent);
ParticleSystemComponent->SetRelativeLocation(FVector(-30.f, 0.f, 110.f));
// PointLightComponent initialization
PointLightComponent = CreateDefaultSubobject<UPointLightComponent>(
TEXT("PointLightComponent"));
PointLightComponent->SetIntensity(1000.f);
PointLightComponent->SetLightColor(FLinearColor(1.f, 0.2f, 0.2f)); //RED color
PointLightComponent->SetupAttachment(RootScene);
PointLightComponent->SetRelativeLocation(FVector(0.f, 0.f, 100.f));
// RotatingMovementComponent initialization
RotatingMovementComponent = CreateDefaultSubobject<URotatingMovementComponent>(
TEXT("RotatingMovementComponent"));
RotatingMovementComponent->SetUpdatedComponent(StaticMeshComponent);
RotatingMovementComponent->RotationRate = FRotator(0.f, 90.f, 0.f);
}
void AElectricChair::PostInitializeComponents()
{
Super::PostInitializeComponents();
AudioComponent->SetSound(SparksSoundCue);
}
void AElectricChair::BeginPlay()
{
Super::BeginPlay();
AudioComponent->Play();
}
void AElectricChair::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
A atribuição do SoundCue no Audio Component precisa ser feita na função PostInitializeComponents(). Esta função é chamada depois que todos os componentes de um Actor foram inicializados.
A hierarquia entre os componentes é feita através da função SetupAttachment(). O único componente que não faz parte da hierarquia é o URotatingMovementComponent porque esta classe não herda de USceneComponent e por isso não possui um Transform.
Compile o código C++ e adicione uma instância de ElectricChair no nível. Veja na aba Details a hierarquia dos componentes:
Inicie o jogo e veja a cadeira elétrica rotacionando com efeito e som de faíscas. Eu adicionei a minha cadeira elétrica em um nível escuro. Ela ficou assim: