Implement basic combat system
This commit is contained in:
@@ -1,24 +1,33 @@
|
||||
#include "EnemySpaceship.h"
|
||||
#include "SpaceshipPawn.h"
|
||||
#include "SpaceshipProjectile.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
AEnemySpaceship::AEnemySpaceship()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
|
||||
ShipMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ShipMesh"));
|
||||
RootComponent = ShipMesh;
|
||||
// Create and setup the enemy mesh
|
||||
EnemyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("EnemyMesh"));
|
||||
RootComponent = EnemyMesh;
|
||||
|
||||
CurrentHealth = MaxHealth;
|
||||
// Disable gravity and physics simulation
|
||||
EnemyMesh->SetSimulatePhysics(false);
|
||||
EnemyMesh->SetEnableGravity(false);
|
||||
|
||||
// Set up collision for the enemy mesh
|
||||
EnemyMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
|
||||
EnemyMesh->SetCollisionObjectType(ECC_Pawn);
|
||||
EnemyMesh->SetCollisionResponseToAllChannels(ECR_Block);
|
||||
EnemyMesh->SetCollisionResponseToChannel(ECC_Pawn, ECR_Ignore); // Ignore other pawns
|
||||
EnemyMesh->SetCollisionResponseToChannel(ECC_GameTraceChannel1, ECR_Ignore); // Ignore player
|
||||
EnemyMesh->SetGenerateOverlapEvents(true);
|
||||
}
|
||||
|
||||
void AEnemySpaceship::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
PlayerPawn = Cast<ASpaceshipPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
|
||||
GetWorldTimerManager().SetTimer(FireTimerHandle, this, &AEnemySpaceship::FireAtPlayer, FireRate, true);
|
||||
// Find the player pawn
|
||||
PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
|
||||
}
|
||||
|
||||
void AEnemySpaceship::Tick(float DeltaTime)
|
||||
@@ -27,66 +36,43 @@ void AEnemySpaceship::Tick(float DeltaTime)
|
||||
|
||||
if (PlayerPawn)
|
||||
{
|
||||
// Calculate distance to player
|
||||
float DistanceToPlayer = FVector::Dist(GetActorLocation(), PlayerPawn->GetActorLocation());
|
||||
// Move towards the player
|
||||
FVector Direction = (PlayerPawn->GetActorLocation() - GetActorLocation()).GetSafeNormal();
|
||||
FVector NewLocation = GetActorLocation() + Direction * MovementSpeed * DeltaTime;
|
||||
SetActorLocation(NewLocation);
|
||||
|
||||
if (DistanceToPlayer <= DetectionRange)
|
||||
{
|
||||
// Look at player
|
||||
FVector Direction = PlayerPawn->GetActorLocation() - GetActorLocation();
|
||||
FRotator NewRotation = Direction.Rotation();
|
||||
SetActorRotation(FMath::RInterpTo(GetActorRotation(), NewRotation, DeltaTime, 2.0f));
|
||||
|
||||
// Move towards player while maintaining some distance
|
||||
float TargetDistance = 1000.0f;
|
||||
if (DistanceToPlayer > TargetDistance)
|
||||
{
|
||||
FVector NewLocation = GetActorLocation() + (Direction.GetSafeNormal() * MovementSpeed * DeltaTime);
|
||||
SetActorLocation(NewLocation);
|
||||
}
|
||||
else if (DistanceToPlayer < TargetDistance - 100.0f)
|
||||
{
|
||||
FVector NewLocation = GetActorLocation() - (Direction.GetSafeNormal() * MovementSpeed * DeltaTime);
|
||||
SetActorLocation(NewLocation);
|
||||
}
|
||||
}
|
||||
// Face towards the player
|
||||
FRotator NewRotation = Direction.Rotation();
|
||||
SetActorRotation(NewRotation);
|
||||
}
|
||||
}
|
||||
|
||||
void AEnemySpaceship::FireAtPlayer()
|
||||
{
|
||||
if (PlayerPawn && FVector::Dist(GetActorLocation(), PlayerPawn->GetActorLocation()) <= DetectionRange)
|
||||
{
|
||||
UWorld* World = GetWorld();
|
||||
if (World)
|
||||
{
|
||||
FVector SpawnLocation = GetActorLocation() + (GetActorForwardVector() * 100.0f);
|
||||
FRotator SpawnRotation = GetActorRotation();
|
||||
FActorSpawnParameters SpawnParams;
|
||||
SpawnParams.Owner = this;
|
||||
SpawnParams.Instigator = GetInstigator();
|
||||
|
||||
ASpaceshipProjectile* Projectile = World->SpawnActor<ASpaceshipProjectile>(
|
||||
ASpaceshipProjectile::StaticClass(),
|
||||
SpawnLocation,
|
||||
SpawnRotation,
|
||||
SpawnParams
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float AEnemySpaceship::TakeDamage(float Damage, FDamageEvent const& DamageEvent,
|
||||
float AEnemySpaceship::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent,
|
||||
AController* EventInstigator, AActor* DamageCauser)
|
||||
{
|
||||
float ActualDamage = Super::TakeDamage(Damage, DamageEvent, EventInstigator, DamageCauser);
|
||||
float DamageToApply = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
|
||||
|
||||
CurrentHealth -= ActualDamage;
|
||||
if (CurrentHealth <= 0)
|
||||
CurrentHealth -= DamageToApply;
|
||||
|
||||
// Debug message
|
||||
if (GEngine)
|
||||
{
|
||||
// Destroy the enemy ship
|
||||
Destroy();
|
||||
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red,
|
||||
FString::Printf(TEXT("Enemy Health: %f"), CurrentHealth));
|
||||
}
|
||||
|
||||
return ActualDamage;
|
||||
if (CurrentHealth <= 0)
|
||||
{
|
||||
Die();
|
||||
}
|
||||
|
||||
return DamageToApply;
|
||||
}
|
||||
|
||||
void AEnemySpaceship::Die()
|
||||
{
|
||||
// Add any death effects here
|
||||
|
||||
// Destroy the enemy
|
||||
Destroy();
|
||||
}
|
||||
Reference in New Issue
Block a user