Implement enemy shooting and scale down for more arcade game feel
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#include "SpaceshipPawn.h"
|
||||
#include "GameFramework/SpringArmComponent.h"
|
||||
#include "Camera/CameraComponent.h"
|
||||
#include "Camera/CameraShakeBase.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
#include "EnhancedInputComponent.h"
|
||||
#include "EnhancedInputSubsystems.h"
|
||||
@@ -59,6 +60,7 @@ ASpaceshipPawn::ASpaceshipPawn()
|
||||
ShipMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Block);
|
||||
ShipMesh->SetCollisionResponseToChannel(ECC_GameTraceChannel1, ECollisionResponse::ECR_Ignore);
|
||||
ShipMesh->SetCollisionResponseToChannel(ECC_Pawn, ECollisionResponse::ECR_Ignore);
|
||||
ShipMesh->SetGenerateOverlapEvents(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +106,11 @@ void ASpaceshipPawn::BeginPlay()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize health and shield values
|
||||
CurrentHealth = MaxHealth;
|
||||
CurrentShield = MaxShield;
|
||||
LastDamageTime = 0.0f;
|
||||
}
|
||||
|
||||
void ASpaceshipPawn::Tick(float DeltaTime)
|
||||
@@ -201,7 +208,7 @@ void ASpaceshipPawn::UpdateArcadeMovement(float DeltaTime)
|
||||
|
||||
// Calculate desired velocity (forward/back + strafe)
|
||||
FVector DesiredVelocity = (ForwardVector * CurrentThrottleInput * MaxSpeed) +
|
||||
(RightVector * CurrentStrafeInput * (MaxSpeed * 0.7f)); // Strafe is slightly slower
|
||||
(RightVector * CurrentStrafeInput * (MaxSpeed * 0.95f)); // Strafe is slightly slower
|
||||
|
||||
// Smoothly interpolate current velocity to desired velocity
|
||||
if (!FMath::IsNearlyZero(CurrentThrottleInput) || !FMath::IsNearlyZero(CurrentStrafeInput))
|
||||
@@ -394,4 +401,198 @@ void ASpaceshipPawn::Fire()
|
||||
void ASpaceshipPawn::ResetFire()
|
||||
{
|
||||
bCanFire = true;
|
||||
}
|
||||
|
||||
float ASpaceshipPawn::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent,
|
||||
AController* EventInstigator, AActor* DamageCauser)
|
||||
{
|
||||
float DamageToApply = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
|
||||
|
||||
// Update last damage time
|
||||
LastDamageTime = GetWorld()->GetTimeSeconds();
|
||||
|
||||
// Stop shield recharge and clear timer
|
||||
GetWorldTimerManager().ClearTimer(ShieldRechargeTimerHandle);
|
||||
|
||||
// Apply damage to shield first
|
||||
if (CurrentShield > 0.0f)
|
||||
{
|
||||
if (CurrentShield >= DamageToApply)
|
||||
{
|
||||
// Shield absorbs all damage
|
||||
CurrentShield -= DamageToApply;
|
||||
DamageToApply = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shield absorbs part of the damage
|
||||
DamageToApply -= CurrentShield;
|
||||
CurrentShield = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply remaining damage to health
|
||||
CurrentHealth -= DamageToApply;
|
||||
|
||||
// Debug message
|
||||
if (GEngine)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red,
|
||||
FString::Printf(TEXT("Player Hit! Health: %.1f, Shield: %.1f"),
|
||||
CurrentHealth, CurrentShield));
|
||||
}
|
||||
|
||||
// Apply visual damage effects
|
||||
ApplyDamageFlash();
|
||||
|
||||
// Play impact effect
|
||||
if (ImpactEffect)
|
||||
{
|
||||
UGameplayStatics::SpawnEmitterAttached(
|
||||
ImpactEffect,
|
||||
ShipMesh,
|
||||
NAME_None,
|
||||
GetActorLocation(),
|
||||
GetActorRotation(),
|
||||
EAttachLocation::KeepWorldPosition
|
||||
);
|
||||
}
|
||||
|
||||
// Play impact sound
|
||||
if (ImpactSound)
|
||||
{
|
||||
UGameplayStatics::PlaySoundAtLocation(
|
||||
this,
|
||||
ImpactSound,
|
||||
GetActorLocation()
|
||||
);
|
||||
}
|
||||
|
||||
// Start shield recharge timer after delay
|
||||
GetWorldTimerManager().SetTimer(
|
||||
ShieldRechargeTimerHandle,
|
||||
this,
|
||||
&ASpaceshipPawn::StartShieldRecharge,
|
||||
ShieldRechargeDelay,
|
||||
false
|
||||
);
|
||||
|
||||
// Check for death
|
||||
if (CurrentHealth <= 0.0f)
|
||||
{
|
||||
Die();
|
||||
}
|
||||
|
||||
return DamageToApply;
|
||||
}
|
||||
|
||||
void ASpaceshipPawn::ApplyDamageFlash()
|
||||
{
|
||||
// Apply material flash effect to indicate damage
|
||||
if (ShipMesh && ShipMesh->GetMaterial(0))
|
||||
{
|
||||
UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(ShipMesh->GetMaterial(0), this);
|
||||
if (DynamicMaterial)
|
||||
{
|
||||
// Assuming the material has a parameter named "FlashColor"
|
||||
DynamicMaterial->SetVectorParameterValue("FlashColor", DamageFlashColor);
|
||||
ShipMesh->SetMaterial(0, DynamicMaterial);
|
||||
|
||||
// Set timer to reset the flash
|
||||
GetWorldTimerManager().SetTimer(
|
||||
DamageFlashTimerHandle,
|
||||
this,
|
||||
&ASpaceshipPawn::ResetDamageFlash,
|
||||
DamageFlashDuration,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ASpaceshipPawn::ResetDamageFlash()
|
||||
{
|
||||
// Reset material flash effect
|
||||
if (ShipMesh && ShipMesh->GetMaterial(0))
|
||||
{
|
||||
UMaterialInstanceDynamic* DynamicMaterial = Cast<UMaterialInstanceDynamic>(ShipMesh->GetMaterial(0));
|
||||
if (DynamicMaterial)
|
||||
{
|
||||
// Reset the flash color (assuming transparent black means no flash)
|
||||
DynamicMaterial->SetVectorParameterValue("FlashColor", FLinearColor(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ASpaceshipPawn::StartShieldRecharge()
|
||||
{
|
||||
// Start continuous shield recharge
|
||||
GetWorldTimerManager().SetTimer(
|
||||
ShieldRechargeTimerHandle,
|
||||
this,
|
||||
&ASpaceshipPawn::RechargeShield,
|
||||
0.1f, // update every 0.1 seconds
|
||||
true // looping
|
||||
);
|
||||
}
|
||||
|
||||
void ASpaceshipPawn::RechargeShield()
|
||||
{
|
||||
// Recharge shield gradually
|
||||
if (CurrentShield < MaxShield)
|
||||
{
|
||||
CurrentShield = FMath::Min(CurrentShield + (ShieldRechargeRate * 0.1f), MaxShield);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shield is full, stop the timer
|
||||
GetWorldTimerManager().ClearTimer(ShieldRechargeTimerHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void ASpaceshipPawn::Die()
|
||||
{
|
||||
// Play death explosion effect
|
||||
UGameplayStatics::SpawnEmitterAtLocation(
|
||||
GetWorld(),
|
||||
ImpactEffect,
|
||||
GetActorLocation(),
|
||||
GetActorRotation(),
|
||||
FVector(3.0f) // Larger explosion for death
|
||||
);
|
||||
|
||||
// Play death sound
|
||||
if (ImpactSound)
|
||||
{
|
||||
UGameplayStatics::PlaySoundAtLocation(
|
||||
this,
|
||||
ImpactSound,
|
||||
GetActorLocation(),
|
||||
2.0f // Louder for death
|
||||
);
|
||||
}
|
||||
|
||||
// Hide the ship mesh
|
||||
if (ShipMesh)
|
||||
{
|
||||
ShipMesh->SetVisibility(false);
|
||||
ShipMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
}
|
||||
|
||||
// Disable input
|
||||
APlayerController* PC = Cast<APlayerController>(GetController());
|
||||
if (PC)
|
||||
{
|
||||
DisableInput(PC);
|
||||
}
|
||||
|
||||
// You could either restart the level after a delay or show a game over screen here
|
||||
// For example:
|
||||
// GetWorldTimerManager().SetTimer(RestartTimerHandle, this, &ASpaceshipPawn::RestartLevel, 3.0f, false);
|
||||
|
||||
// For now, just log the death
|
||||
if (GEngine)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("PLAYER DIED!"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user