In this article, we will create a subclass of AActor containing several components to show in practice how they are used in C++.
These are the components that will be used in the example:
- Scene Component: It is used as the Actor's Root Component.
- Static Mesh Component: It contains a Static Mesh that visually represents the Actor.
- Capsule Component: Component used for the collision test.
- Particle System Component: Contains a particle emitter.
- Point Light Component: Component that emits light in all directions from a point.
- Rotating Movement Component: Used to constantly rotate the Actor.
- Audio Component: Used to play sound at the Actor's location.
Example usage:
For this example, you need a project with the Starter Content.
Let's create an electric chair. All of its functionality will be done through components. It will have a particle emitter simulating the sparks and an audio component with the sound of the sparks. It will contain a red point of light and will be in constant rotation.
Create a C++ class with the name ElectricChair using the Actor class as the parent class. In the file ElectricChair.h define all the components and declare the function PostInitializeComponents(), as shown in the code below:
#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;
};
In the cpp file we have to add the #include lines with the header files of the component classes. To learn how to #include a class, look for the class on the Unreal Engine API Reference.
In the class constructor, the Assets of Static Mesh, Particle System, and SoundCue are loaded. To obtain the path of an Asset in the Unreal editor, right-click the Asset and select the Copy Reference option.
The constructor contains the component initializations. The ElectricChair.cpp file should have this content:
#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);
}
The assignment of SoundCue to the Audio Component needs to be done in the PostInitializeComponents() function. This function is called after all components of an Actor have been initialized.
The hierarchy between components is done through the SetupAttachment() function. The only component that is not part of the hierarchy is the URotatingMovementComponent because this class does not inherit from USceneComponent and therefore does not have a Transform.
Compile the C++ code and add an instance of ElectricChair at the level. See the hierarchy of components in the Details tab:
Start the game and see the electric chair rotating with sparks effect and sound. I added my electric chair on a dark level. It looked like this: