Hi, sure.
PawnTank.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "PawnTank.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
APawnTank::APawnTank()
{
SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("Spring Arm"));
SpringArm->SetupAttachment(RootComponent);
Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
Camera->SetupAttachment(SpringArm);
}
// Called when the game starts or when spawned
void APawnTank::BeginPlay()
{
Super::BeginPlay();
PlayerControllerRef = Cast<APlayerController>(GetController());
}
void APawnTank::HandleDestruction()
{
Super::HandleDestruction();
// Hide Player, TODO - Create new function to handle this.
bIsPlayerAlive = false;
SetActorHiddenInGame(true);
SetActorTickEnabled(false);
}
bool APawnTank::GetIsPlayerAlive()
{
return bIsPlayerAlive;
}
// Called every frame
void APawnTank::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
Rotate();
Move();
if (PlayerControllerRef)
{
FHitResult TraceHitResult;
PlayerControllerRef->GetHitResultUnderCursor(ECC_Visibility, false, TraceHitResult);
FVector HitLocation = TraceHitResult.ImpactPoint;
RotateTurret(HitLocation);
}
}
// Called to bind functionality to input
void APawnTank::SetupPlayerInputComponent(UInputComponent *PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAxis("MoveForward", this, &APawnTank::CalculateMoveInput);
PlayerInputComponent->BindAxis("Turn", this, &APawnTank::CalculateRotateInput);
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &APawnTank::Fire);
}
void APawnTank::CalculateMoveInput(float Value)
{
MoveDirection = FVector(Value * MoveSpeed * GetWorld()->DeltaTimeSeconds, 0, 0);
}
void APawnTank::CalculateRotateInput(float Value)
{
float RotateAmount = Value * RotateSpeed * GetWorld()->DeltaTimeSeconds;
FRotator Rotation = FRotator(0, RotateAmount, 0);
RotationDirection = FQuat(Rotation);
}
void APawnTank::Move()
{
AddActorLocalOffset(MoveDirection, true);
}
void APawnTank::Rotate()
{
AddActorLocalRotation(RotationDirection, true);
}
ProjectileBase.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "ProjectileBase.h"
#include "Components/StaticMeshComponent.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Kismet/GameplayStatics.h"
#include "Particles/ParticleSystemComponent.h"
// Sets default values
AProjectileBase::AProjectileBase()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
ProjectileMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ProjectileMesh"));
ProjectileMesh->OnComponentHit.AddDynamic(this, &AProjectileBase::OnHit);
RootComponent = ProjectileMesh;
ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("Projectile Movement"));
ProjectileMovement->InitialSpeed = MovementSpeed;
ProjectileMovement->MaxSpeed = MovementSpeed;
ParticleTrail = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Particle Trail"));
ParticleTrail->SetupAttachment(RootComponent);
InitialLifeSpan = 3.0f;
}
// Called when the game starts or when spawned
void AProjectileBase::BeginPlay()
{
Super::BeginPlay();
UGameplayStatics::PlaySoundAtLocation(this, LaunchSound, GetActorLocation());
}
void AProjectileBase::OnHit(UPrimitiveComponent *HitComp, AActor *OtherActor, UPrimitiveComponent *OtherComp, FVector NormalImpulse, const FHitResult &Hit)
{
// Try to get a reference to the owning class.
AActor *MyOwner = GetOwner();
// If for some reason we can't get a valid reference, return as we need to check against the owner.
if (!MyOwner)
{
return;
}
// If the other actor ISN'T self OR owner AND exists, then apply damage.
if (OtherActor && OtherActor != this && OtherActor != MyOwner)
{
UGameplayStatics::ApplyDamage(OtherActor, Damage, MyOwner->GetInstigatorController(), this, DamageType);
UGameplayStatics::SpawnEmitterAtLocation(this, HitParticle, GetActorLocation());
UGameplayStatics::PlaySoundAtLocation(this, HitSound, GetActorLocation());
GetWorld()->GetFirstPlayerController()->ClientPlayCameraShake(HitShake);
Destroy();
}
}
ProjectileBase.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ProjectileBase.generated.h"
class UProjectileMovementComponent;
UCLASS()
class TOONTANKS_API AProjectileBase : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
UProjectileMovementComponent *ProjectileMovement;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
UStaticMeshComponent *ProjectileMesh;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
UParticleSystemComponent* ParticleTrail;
// VARIABLES
UPROPERTY(EditDefaultsOnly, Category = "Damage")
TSubclassOf<UDamageType> DamageType;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Move", meta = (AllowPrivateAccess = "true"))
float MovementSpeed = 1300;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Damage", meta = (AllowPrivateAccess = "true"))
float Damage = 50;
UPROPERTY(EditAnywhere, Category = "Effects")
UParticleSystem *HitParticle;
UPROPERTY(EditAnywhere, Category = "Effects")
USoundBase* HitSound;
UPROPERTY(EditAnywhere, Category = "Effects")
USoundBase* LaunchSound;
UPROPERTY(EditAnywhere, Category = "Effects")
TSubclassOf<UMatineeCameraShake> HitShake;
// FUNCTIONS
UFUNCTION()
void OnHit(UPrimitiveComponent *HitComp, AActor *OtherActor, UPrimitiveComponent *OtherComp, FVector NormalImpulse, const FHitResult &Hit);
public:
// Sets default values for this actor's properties
AProjectileBase();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
};
PawnTurret.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "PawnTurret.h"
#include "Kismet/GameplayStatics.h"
#include "ToonTanks/Pawn/PawnTank.h"
// Called when the game starts or when spawned
void APawnTurret::BeginPlay()
{
Super::BeginPlay();
GetWorld()->GetTimerManager().SetTimer(FireRateTimerHandle, this, &APawnTurret::CheckFireCondition, FireRate, true);
PlayerPawn = Cast<APawnTank>(UGameplayStatics::GetPlayerPawn(this, 0));
}
void APawnTurret::HandleDestruction()
{
// Call base pawn class HandleDestruction to play effects
Super::HandleDestruction();
Destroy();
}
// Called every frame
void APawnTurret::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (!PlayerPawn || ReturnDistanceToPlayer() > FireRange)
{
return;
}
RotateTurret(PlayerPawn->GetActorLocation());
}
void APawnTurret::CheckFireCondition()
{
// If Player == null || is DEAD THE BAIL!!
if (!PlayerPawn || !PlayerPawn->GetIsPlayerAlive())
{
return;
}
// If Player IS in range THEN FIRE!!
if (ReturnDistanceToPlayer() <= FireRange)
{
Fire();
}
}
float APawnTurret::ReturnDistanceToPlayer()
{
if (!PlayerPawn)
{
return 0.0f;
}
return FVector::Dist(PlayerPawn->GetActorLocation(), GetActorLocation());
}
PawnTurret.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "ToonTanks/Pawn/PawnBase.h"
#include "PawnTurret.generated.h"
class APawnTank;
UCLASS()
class TOONTANKS_API APawnTurret : public APawnBase
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Combat", meta = (AllowPrivateAccess = true))
float FireRate = 2.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Combat", meta = (AllowPrivateAccess = true))
float FireRange = 500.0f;
FTimerHandle FireRateTimerHandle;
APawnTank *PlayerPawn;
void CheckFireCondition();
float ReturnDistanceToPlayer();
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
virtual void HandleDestruction() override;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
};