228 lines
7.7 KiB
C++
228 lines
7.7 KiB
C++
#include "SpaceShooterHUD.h"
|
|
#include "SpaceShooterGameMode.h"
|
|
#include "Engine/Canvas.h"
|
|
#include "Engine/Font.h"
|
|
#include "SpaceshipPawn.h"
|
|
#include "UObject/ConstructorHelpers.h"
|
|
|
|
ASpaceShooterHUD::ASpaceShooterHUD()
|
|
{
|
|
// Find and set the default font
|
|
static ConstructorHelpers::FObjectFinder<UFont> FontObj(TEXT("/Engine/EngineFonts/RobotoDistanceField"));
|
|
TextFont = FontObj.Object;
|
|
GameOverStartTime = 0.0f;
|
|
}
|
|
|
|
ASpaceshipPawn* ASpaceShooterHUD::GetPlayerPawn() const
|
|
{
|
|
APlayerController* PC = GetWorld()->GetFirstPlayerController();
|
|
if (PC)
|
|
{
|
|
return Cast<ASpaceshipPawn>(PC->GetPawn());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Add this new function for drawing the bars
|
|
void ASpaceShooterHUD::DrawStatusBars()
|
|
{
|
|
if (!Canvas) return;
|
|
|
|
ASpaceshipPawn* PlayerPawn = GetPlayerPawn();
|
|
if (!PlayerPawn) return;
|
|
|
|
// Get the canvas size
|
|
const float ScreenWidth = Canvas->SizeX;
|
|
const float ScreenHeight = Canvas->SizeY;
|
|
|
|
// Calculate positions for the bars (top right corner)
|
|
float StartX = ScreenWidth - BarWidth - BarPadding;
|
|
float HealthY = BarPadding;
|
|
float ShieldY = HealthY + BarHeight + BarPadding;
|
|
|
|
// Get current health and shield values
|
|
float HealthPercent = PlayerPawn->GetCurrentHealth() / PlayerPawn->GetMaxHealth();
|
|
float ShieldPercent = PlayerPawn->GetCurrentShield() / PlayerPawn->GetMaxShield();
|
|
|
|
// Clamp values between 0 and 1
|
|
HealthPercent = FMath::Clamp(HealthPercent, 0.0f, 1.0f);
|
|
ShieldPercent = FMath::Clamp(ShieldPercent, 0.0f, 1.0f);
|
|
|
|
// Draw health bar background
|
|
FCanvasBoxItem HealthBG(FVector2D(StartX, HealthY), FVector2D(BarWidth, BarHeight));
|
|
HealthBG.SetColor(BackgroundBarColor);
|
|
Canvas->DrawItem(HealthBG);
|
|
|
|
// Draw health bar fill
|
|
FCanvasBoxItem HealthFill(FVector2D(StartX, HealthY), FVector2D(BarWidth * HealthPercent, BarHeight));
|
|
HealthFill.SetColor(HealthBarColor);
|
|
Canvas->DrawItem(HealthFill);
|
|
|
|
// Draw shield bar background
|
|
FCanvasBoxItem ShieldBG(FVector2D(StartX, ShieldY), FVector2D(BarWidth, BarHeight));
|
|
ShieldBG.SetColor(BackgroundBarColor);
|
|
Canvas->DrawItem(ShieldBG);
|
|
|
|
// Draw shield bar fill
|
|
FCanvasBoxItem ShieldFill(FVector2D(StartX, ShieldY), FVector2D(BarWidth * ShieldPercent, BarHeight));
|
|
ShieldFill.SetColor(ShieldBarColor);
|
|
Canvas->DrawItem(ShieldFill);
|
|
|
|
// Draw text labels
|
|
FString HealthText = FString::Printf(TEXT("Health: %.0f%%"), HealthPercent * 100);
|
|
FString ShieldText = FString::Printf(TEXT("Shield: %.0f%%"), ShieldPercent * 100);
|
|
|
|
// Draw text over the bars
|
|
DrawText(HealthText, FLinearColor::White, StartX + 5, HealthY + 2, TextFont, 0.8f);
|
|
DrawText(ShieldText, FLinearColor::White, StartX + 5, ShieldY + 2, TextFont, 0.8f);
|
|
}
|
|
|
|
void ASpaceShooterHUD::DrawHUD()
|
|
{
|
|
Super::DrawHUD();
|
|
|
|
ASpaceShooterGameMode* GameMode = GetGameMode();
|
|
if (!GameMode) return;
|
|
|
|
if (!GameMode->IsGameOver())
|
|
{
|
|
DrawGameplayHUD();
|
|
}
|
|
else
|
|
{
|
|
DrawGameOverScreen();
|
|
}
|
|
}
|
|
|
|
void ASpaceShooterHUD::DrawGameplayHUD()
|
|
{
|
|
ASpaceShooterGameMode* GameMode = GetGameMode();
|
|
if (!GameMode) return;
|
|
|
|
// Draw timer
|
|
int32 Minutes = FMath::FloorToInt(GameMode->GetRemainingTime() / 60.0f);
|
|
int32 Seconds = FMath::FloorToInt(FMath::Fmod(GameMode->GetRemainingTime(), 60.0f));
|
|
FString TimeString = FString::Printf(TEXT("Time: %02d:%02d"), Minutes, Seconds);
|
|
DrawText(TimeString, FLinearColor::White, 50, 50, TextFont);
|
|
|
|
// Draw kill count
|
|
FString KillString = FString::Printf(TEXT("Kills: %d"), GameMode->GetKillCount());
|
|
DrawText(KillString, FLinearColor::White, 50, 100, TextFont);
|
|
|
|
// Draw status bars
|
|
DrawStatusBars();
|
|
}
|
|
|
|
void ASpaceShooterHUD::DrawGameOverBackground()
|
|
{
|
|
if (!Canvas) return;
|
|
|
|
// Draw a semi-transparent black background
|
|
FCanvasBoxItem BoxItem(FVector2D(0, 0), FVector2D(Canvas->SizeX, Canvas->SizeY));
|
|
BoxItem.SetColor(FLinearColor(0.0f, 0.0f, 0.0f, 0.7f));
|
|
Canvas->DrawItem(BoxItem);
|
|
}
|
|
|
|
void ASpaceShooterHUD::DrawGameOverText(const FString& Text, const FVector2D& Position, const FLinearColor& Color, float Scale)
|
|
{
|
|
if (!Canvas || !TextFont) return;
|
|
|
|
float TextWidth, TextHeight;
|
|
GetTextSize(Text, TextWidth, TextHeight, TextFont, Scale);
|
|
|
|
// Draw text shadow
|
|
DrawText(Text, FLinearColor(0.0f, 0.0f, 0.0f, Color.A * 0.5f),
|
|
Position.X + 3.0f, Position.Y + 3.0f, TextFont, Scale);
|
|
|
|
// Draw main text
|
|
DrawText(Text, Color, Position.X, Position.Y, TextFont, Scale);
|
|
}
|
|
|
|
void ASpaceShooterHUD::DrawGameOverScreen()
|
|
{
|
|
ASpaceShooterGameMode* GameMode = GetGameMode();
|
|
if (!GameMode || !Canvas) return;
|
|
|
|
// Initialize GameOverStartTime if needed
|
|
if (GameOverStartTime == 0.0f)
|
|
{
|
|
GameOverStartTime = GetWorld()->GetTimeSeconds();
|
|
}
|
|
|
|
// Draw darkened background
|
|
DrawGameOverBackground();
|
|
|
|
const FVector2D ViewportSize(Canvas->SizeX, Canvas->SizeY);
|
|
const float CurrentTime = GetWorld()->GetTimeSeconds();
|
|
const float TimeSinceGameOver = CurrentTime - GameOverStartTime;
|
|
|
|
// Calculate pulsating alpha for "GAME OVER" text
|
|
float PulsatingAlpha = FMath::Lerp(PulsateMinAlpha, PulsateMaxAlpha,
|
|
(FMath::Sin(TimeSinceGameOver * PulsateSpeed) + 1.0f) * 0.5f);
|
|
|
|
// Calculate vertical positions
|
|
float CenterY = ViewportSize.Y * 0.4f; // Slightly above center
|
|
float Spacing = 60.0f * GameOverScale;
|
|
|
|
// Draw "GAME OVER" with pulsating effect
|
|
FLinearColor PulsatingColor = GameOverTextColor;
|
|
PulsatingColor.A = PulsatingAlpha;
|
|
|
|
FString GameOverText = TEXT("GAME OVER");
|
|
float TextWidth, TextHeight;
|
|
GetTextSize(GameOverText, TextWidth, TextHeight, TextFont, GameOverScale);
|
|
|
|
DrawGameOverText(GameOverText,
|
|
FVector2D((ViewportSize.X - TextWidth) * 0.5f, CenterY),
|
|
PulsatingColor,
|
|
GameOverScale);
|
|
|
|
// Draw stats with scaling animations
|
|
const float StatsScale = 1.5f;
|
|
float StatsY = CenterY + Spacing;
|
|
|
|
// Time Survived
|
|
int32 TotalSeconds = FMath::RoundToInt(GameMode->GetGameDuration() - GameMode->GetRemainingTime());
|
|
int32 Minutes = TotalSeconds / 60;
|
|
int32 Seconds = TotalSeconds % 60;
|
|
FString TimeText = FString::Printf(TEXT("Time Survived: %02d:%02d"), Minutes, Seconds);
|
|
GetTextSize(TimeText, TextWidth, TextHeight, TextFont, StatsScale);
|
|
DrawGameOverText(TimeText,
|
|
FVector2D((ViewportSize.X - TextWidth) * 0.5f, StatsY),
|
|
StatsTextColor,
|
|
StatsScale);
|
|
|
|
// Kill Count
|
|
StatsY += Spacing * 0.7f;
|
|
FString KillText = FString::Printf(TEXT("Enemies Destroyed: %d"), GameMode->GetKillCount());
|
|
GetTextSize(KillText, TextWidth, TextHeight, TextFont, StatsScale);
|
|
DrawGameOverText(KillText,
|
|
FVector2D((ViewportSize.X - TextWidth) * 0.5f, StatsY),
|
|
StatsTextColor,
|
|
StatsScale);
|
|
|
|
// Calculate final score based on time and kills
|
|
int32 FinalScore = GameMode->GetKillCount() * 100 + TotalSeconds * 10;
|
|
StatsY += Spacing * 0.7f;
|
|
FString ScoreText = FString::Printf(TEXT("Final Score: %d"), FinalScore);
|
|
GetTextSize(ScoreText, TextWidth, TextHeight, TextFont, StatsScale);
|
|
DrawGameOverText(ScoreText,
|
|
FVector2D((ViewportSize.X - TextWidth) * 0.5f, StatsY),
|
|
StatsTextColor,
|
|
StatsScale);
|
|
|
|
// Draw restart text with bounce effect
|
|
float BounceOffset = FMath::Sin(TimeSinceGameOver * 3.0f) * 5.0f;
|
|
StatsY += Spacing * 1.2f;
|
|
FString RestartText = TEXT("Press R to Restart");
|
|
GetTextSize(RestartText, TextWidth, TextHeight, TextFont, StatsScale);
|
|
DrawGameOverText(RestartText,
|
|
FVector2D((ViewportSize.X - TextWidth) * 0.5f, StatsY + BounceOffset),
|
|
RestartTextColor,
|
|
StatsScale);
|
|
}
|
|
|
|
ASpaceShooterGameMode* ASpaceShooterHUD::GetGameMode() const
|
|
{
|
|
return Cast<ASpaceShooterGameMode>(GetWorld()->GetAuthGameMode());
|
|
} |