Pages

segunda-feira, 12 de abril de 2021

EnemyCannon: C++ implementation file

In the previous article, we analyzed the contents of the 1st version of the EnemyCannon.h file. In this article, the contents of the equivalent EnemyCannon.cpp file will be explained.

At the beginning of the file, there is the inclusion of the necessary header files using the #include lines. In the constructor, we have the initialization of the components and of the FireRate variable.

#include "EnemyCannon.h"
#include "EnemyProjectile.h"
#include "Components/ArrowComponent.h"
#include "Kismet/GameplayStatics.h"
#include "PlayerProjectile.h"

// Sets default values
AEnemyCannon::AEnemyCannon()
{
  PrimaryActorTick.bCanEverTick = true;
	
  RootScene = CreateDefaultSubobject<USceneComponent>(TEXT("RootScene"));
  RootComponent = RootScene;

  StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
  StaticMesh->SetCollisionProfileName(
                       UCollisionProfile::BlockAllDynamic_ProfileName);
  StaticMesh->SetupAttachment(RootScene);
	
  ProjectileSpawnLocation = CreateDefaultSubobject<UArrowComponent>(
                                                  TEXT("ProjectileSpawnLocation"));
  ProjectileSpawnLocation->SetupAttachment(StaticMesh);

  FireRate = 5.f;	
}

// Called every frame
void AEnemyCannon::Tick(float DeltaTime)
{
  Super::Tick(DeltaTime);

  FVector Direction = PlayerPawn->GetActorLocation() 
                      - StaticMesh->GetComponentLocation();
  
  FRotator Rotator = FVector(Direction.X, Direction.Y, 0).Rotation();
  
  StaticMesh->SetWorldRotation(Rotator);
}

// Called when the game starts or when spawned
void AEnemyCannon::BeginPlay()
{
  Super::BeginPlay();
	
  PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
	
  GetWorldTimerManager().SetTimer(ShotTimerHandle, this, 
                                  &AEnemyCannon::ShootCannon, FireRate, true);	
}


void AEnemyCannon::ShootCannon()
{	
  GetWorld()->SpawnActor<AEnemyProjectile>(ProjectileClass, 
                         ProjectileSpawnLocation->GetComponentTransform() );
}

In the Tick() function there is the logic for the cannon to always aim in the direction of the player. First, we calculate the Direction vector by taking the player's Location vector and subtracting the cannon's Location vector.

The FVector structure has a function called Rotation() that returns a FRotator in the direction indicated by the vector. An FVector was created based on the Direction vector but disregarding the Z coordinate so that the cannon does not rotate up and down. The FRotator resulting from this new FVector was used to define the current cannon rotation.

In the BeginPlay() function, the reference to the instance representing the player is obtained and stored in the PlayerPawn variable. Then we have the creation of the Timer, whose reference will be stored in ShotTimerHandle, and which will call the ShootCannon function periodically using the value in the FireRate variable as the time interval.

In the ShootCannon() function we have the creation of the projectile based on the class that is stored in ProjectileClass using the Transform of the ProjectileSpawnLocation component to define the position and rotation of the projectile.

In the next article, we'll look at the variables and functions needed to count the Hits and destroy the cannon.


Table of Contents C++