In this article, we will create a C++ base class to represent the Homing projectiles that are fired by enemy cannons.
In the Content Browser, access the TutoPart3 folder that is inside the C++ Classes folder. Right-click on free space and choose the New C++ Class... option:
On the next screen, choose the Actor class as the parent class and click the Next button.
The EnemyProjectile class will use four types of components:
- USphereComponent: It is used as the Root component and for collision testing.
- UStaticMeshComponent: Contains the Static Mesh that will visually represent the projectile.
- UParticleSystemComponent: Component with a particle emitter that will be used to simulate a fire effect on the projectile.
- UProjectileMovementComponent: Component used to move the projectile. It will be configured to follow the player.
Add the declaration of the components in the EnemyProjectile.h file that will look like this:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "EnemyProjectile.generated.h"
UCLASS()
class TUTOPART3_API AEnemyProjectile : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AEnemyProjectile();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
UStaticMeshComponent* StaticMesh;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
class USphereComponent* CollisionComponent;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
class UParticleSystemComponent* Particles;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
class UProjectileMovementComponent* ProjectileMovement;
};
In the EnemyProjectile.cpp file, we have the initialization of the components done in the constructor. Don't forget to add the #include lines for the components.
#include "EnemyProjectile.h"
#include "Engine/CollisionProfile.h"
#include "Components/SphereComponent.h"
#include "Particles/ParticleSystemComponent.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Kismet/GameplayStatics.h"
// Sets default values
AEnemyProjectile::AEnemyProjectile()
{
PrimaryActorTick.bCanEverTick = true;
InitialLifeSpan = 10.f;
CollisionComponent = CreateDefaultSubobject<USphereComponent>(
TEXT("CollisionComponent"));
RootComponent = CollisionComponent;
CollisionComponent->InitSphereRadius(25.f);
CollisionComponent->SetCollisionProfileName(
UCollisionProfile::BlockAllDynamic_ProfileName);
StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
StaticMesh->SetupAttachment(CollisionComponent);
Particles = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Particles"));
Particles->SetupAttachment(StaticMesh);
ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(
TEXT("ProjectileMovement"));
ProjectileMovement->InitialSpeed = 300.f;
ProjectileMovement->MaxSpeed = 300.f;
ProjectileMovement->bRotationFollowsVelocity = true;
ProjectileMovement->bIsHomingProjectile = true;
ProjectileMovement->HomingAccelerationMagnitude = 300.f;
ProjectileMovement->ProjectileGravityScale = 0.f;
}
// Called when the game starts or when spawned
void AEnemyProjectile::BeginPlay()
{
Super::BeginPlay();
APawn* PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
if(PlayerPawn)
{
ProjectileMovement->HomingTargetComponent = PlayerPawn->GetRootComponent();
}
}
// Called every frame
void AEnemyProjectile::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
I did the following steps to configure the UProjectileMovementComponent as a Homing projectile:
- I assigned true to the variable bRotationFollowsVelocity so that the projectile rotates when it changes direction.
- I assigned true to the variable bIsHomingProjectile to indicate that this is a Homing Projectile.
- I assigned a value for the HomingAccelerationMagnitude variable that indicates the acceleration that the projectile will move towards the target. I used the same value as the velocity of the projectile.
- I removed the force of gravity from the projectile by assigning a value of 0 to the ProjectileGravityScale variable.
- The last step is to assign a USceneComponent to the variable HomingTargetComponent that will be used as a target. This is done in the BeginPlay() function. The target is the player's RootComponent.
Compile the C++ code. The Static Mesh and Particle System Assets will be selected in the child Blueprints. Besides that, the initial values assigned to the components can be modified in child Blueprints.