From df8bc6c7a8cb643056029616c897d6caa70530e5 Mon Sep 17 00:00:00 2001 From: nathan Date: Mon, 18 May 2026 21:06:20 -0700 Subject: [PATCH] Complete MVP HUD frame --- AGRARIAN_DEVELOPMENT_ROADMAP.md | 2 +- Scripts/verify_mvp_hud_frame.py | 46 ++++++++++++++++++++++++ Source/AgrarianGame/AgrarianDebugHUD.cpp | 28 +++++++++++++++ Source/AgrarianGame/AgrarianDebugHUD.h | 4 +++ 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 Scripts/verify_mvp_hud_frame.py diff --git a/AGRARIAN_DEVELOPMENT_ROADMAP.md b/AGRARIAN_DEVELOPMENT_ROADMAP.md index c2f44db..8b958eb 100644 --- a/AGRARIAN_DEVELOPMENT_ROADMAP.md +++ b/AGRARIAN_DEVELOPMENT_ROADMAP.md @@ -798,7 +798,7 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe - [x] Let players choose a realistic young adult male or female character with average proportions for the MVP. Added a selectable MVP character archetype enum, visible selected state, keyboard selection, and `AgrarianSelectCharacter male|female` dev command while keeping both choices on the same MVP survival baseline until real character art arrives. - [x] Add join server screen. Added a native `JoinServer` frontend screen showing the selected character and `play.agrariangame.com:7777`, with keyboard flow from character selection and a dev command to display the screen directly. - [x] Add loading screen. Added a native `Loading` frontend screen with Ground Zero preparation copy, selected character/server context, a deterministic placeholder progress bar, and join-screen keyboard flow into loading. -- [~] Add HUD. +- [x] Add HUD. Completed the MVP HUD pass with a separate `bShowMvpHudFrame` top status frame showing Ground Zero context, alive/dead state, health, food, water, and body temperature, while keeping the deeper developer overlay separately toggleable. - [ ] Add inventory UI. - [ ] Add crafting UI. - [ ] Add interaction prompts. diff --git a/Scripts/verify_mvp_hud_frame.py b/Scripts/verify_mvp_hud_frame.py new file mode 100644 index 0000000..06d467f --- /dev/null +++ b/Scripts/verify_mvp_hud_frame.py @@ -0,0 +1,46 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +FILES = { + "AgrarianDebugHUD.h": ROOT / "Source" / "AgrarianGame" / "AgrarianDebugHUD.h", + "AgrarianDebugHUD.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianDebugHUD.cpp", + "AGRARIAN_DEVELOPMENT_ROADMAP.md": ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md", +} + +EXPECTED = { + "AgrarianDebugHUD.h": [ + "bShowMvpHudFrame", + "DrawMvpHudFrame", + ], + "AgrarianDebugHUD.cpp": [ + "DrawMvpHudFrame(AgrarianCharacter)", + "AAgrarianDebugHUD::DrawMvpHudFrame", + "AGRARIAN MVP | Ground Zero", + "Health %.0f Food %.0f Water %.0f Temp %.1fC", + "bShowDebugHUD", + ], + "AGRARIAN_DEVELOPMENT_ROADMAP.md": [ + "[x] Add HUD.", + "`bShowMvpHudFrame`", + "developer overlay separately toggleable", + ], +} + + +def main(): + missing = [] + for label, path in FILES.items(): + text = path.read_text(encoding="utf-8") + for snippet in EXPECTED[label]: + if snippet not in text: + missing.append(f"{label}: {snippet}") + + if missing: + raise RuntimeError("MVP HUD frame verification failed: " + "; ".join(missing)) + + print("Agrarian MVP HUD frame verification complete.") + + +if __name__ == "__main__": + main() diff --git a/Source/AgrarianGame/AgrarianDebugHUD.cpp b/Source/AgrarianGame/AgrarianDebugHUD.cpp index 98db74d..0833c5d 100644 --- a/Source/AgrarianGame/AgrarianDebugHUD.cpp +++ b/Source/AgrarianGame/AgrarianDebugHUD.cpp @@ -23,6 +23,7 @@ void AAgrarianDebugHUD::DrawHUD() return; } + DrawMvpHudFrame(AgrarianCharacter); DrawInteractionPrompt(AgrarianCharacter); DrawCriticalStats(AgrarianCharacter->GetSurvivalComponent()); const float InventoryBottomY = DrawInventoryPanel(AgrarianCharacter); @@ -40,6 +41,33 @@ void AAgrarianDebugHUD::DrawHUD() } } +void AAgrarianDebugHUD::DrawMvpHudFrame(const AAgrarianGameCharacter* AgrarianCharacter) +{ + if (!bShowMvpHudFrame || !AgrarianCharacter || !Canvas) + { + return; + } + + const UAgrarianSurvivalComponent* SurvivalComponent = AgrarianCharacter->GetSurvivalComponent(); + const FAgrarianSurvivalSnapshot* Survival = SurvivalComponent ? &SurvivalComponent->Survival : nullptr; + const float Scale = FMath::Max(0.25f, TextScale); + const float PanelWidth = FMath::Min(Canvas->ClipX - 64.0f, 620.0f * Scale); + const float PanelHeight = 54.0f * Scale; + const float X = (Canvas->ClipX - PanelWidth) * 0.5f; + const float Y = 26.0f; + + DrawRect(FLinearColor(0.02f, 0.025f, 0.02f, 0.68f), X, Y, PanelWidth, PanelHeight); + DrawRect(FLinearColor(0.45f, 0.72f, 0.40f, 0.92f), X, Y, PanelWidth, 3.0f * Scale); + + const FString StateText = Survival && Survival->bIsDead ? TEXT("DEAD") : TEXT("ALIVE"); + const FString CoreStats = Survival + ? FString::Printf(TEXT("Health %.0f Food %.0f Water %.0f Temp %.1fC"), Survival->Health, Survival->Hunger, Survival->Thirst, Survival->BodyTemperature) + : FString(TEXT("Survival unavailable")); + const FString HudText = FString::Printf(TEXT("AGRARIAN MVP | Ground Zero | %s | %s"), *StateText, *CoreStats); + + DrawText(HudText, FColor(225, 235, 220), X + (18.0f * Scale), Y + (16.0f * Scale), nullptr, 0.86f * Scale, false); +} + void AAgrarianDebugHUD::DrawInteractionPrompt(const AAgrarianGameCharacter* AgrarianCharacter) { if (!bShowInteractionPrompt || !AgrarianCharacter || !AgrarianCharacter->HasInteractionPrompt() || !Canvas) diff --git a/Source/AgrarianGame/AgrarianDebugHUD.h b/Source/AgrarianGame/AgrarianDebugHUD.h index 7d72532..d5091ed 100644 --- a/Source/AgrarianGame/AgrarianDebugHUD.h +++ b/Source/AgrarianGame/AgrarianDebugHUD.h @@ -21,6 +21,9 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD") bool bShowDebugHUD = true; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD") + bool bShowMvpHudFrame = true; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD") bool bShowCriticalStatsHUD = true; @@ -52,6 +55,7 @@ public: float PromptTextScale = 1.15f; protected: + void DrawMvpHudFrame(const class AAgrarianGameCharacter* AgrarianCharacter); void DrawInteractionPrompt(const class AAgrarianGameCharacter* AgrarianCharacter); void DrawCriticalStats(const UAgrarianSurvivalComponent* SurvivalComponent); float DrawInventoryPanel(const class AAgrarianGameCharacter* AgrarianCharacter);