segunda-feira, 12 de abril de 2021

EnemyCannon: Arquivo de implementação C++

No artigo anterior, analisamos o conteúdo da 1ª versão do arquivo EnemyCannon.h. Neste artigo, será explicado o conteúdo do arquivo EnemyCannon.cpp equivalente.

No início do arquivo tem a inclusão dos arquivos cabeçalhos necessários usando as linhas #include. No construtor temos a inicialização dos componentes e da variável FireRate

#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() );
}

Na função Tick() é feito a lógica para que o canhão sempre aponte na direção do jogador. Primeiro, calculamos o vetor da Direção (Direction) pegando o vetor Location do jogador e subtraindo o vetor Location do canhão.

A estrutura FVector possui uma função chamada Rotation() que retorna um FRotator na direção indicada pelo vetor. Foi criado um FVector baseado no vetor Direction mas desconsiderando a coordenada Z para que o canhão não rotacione para cima e para baixo. O FRotator resultante deste novo FVector foi usado para definir a rotação atual do canhão.

Na função BeginPlay() é obtida a referência à instância que representa o jogador e armazenada na variável PlayerPawn. Depois temos a criação do Timer, cuja referência será armazenada em ShotTimerHandle, e que chamará a função ShootCannon periodicamente usando como intervalo de tempo o valor que está na variável FireRate.

Na função ShootCannon() temos a criação do projétil baseado na classe que está armazenada em ProjectileClass usando o Transform do componente ProjectileSpawnLocation para definir a posição e rotação do projétil. 

No próximo artigo veremos as variáveis e funções necessárias para contar os Hits e destruir o canhão.


Sumário C++