Finish work

This commit is contained in:
Michal Pikulski
2025-12-04 02:16:38 +01:00
parent 88049ac97c
commit 9b71b00441
17 changed files with 1684 additions and 127 deletions

View File

@@ -19,14 +19,10 @@ namespace Minigames.FortFight.UI
[SerializeField] private int playerIndex = 0;
[Header("References")]
[Tooltip("Ammunition manager (shared between both players)")]
[SerializeField] private AmmunitionManager ammunitionManager;
[Tooltip("This player's slingshot controller")]
[SerializeField] private SlingshotController slingshotController;
[Tooltip("Turn manager to subscribe to turn events")]
[SerializeField] private TurnManager turnManager;
// Note: AmmunitionManager and TurnManager accessed via singletons
[Header("UI")]
[Tooltip("Array of ammo buttons in this panel")]
@@ -44,21 +40,11 @@ namespace Minigames.FortFight.UI
base.OnManagedAwake();
// Validate references
if (ammunitionManager == null)
{
Logging.Error($"[AmmunitionPanel] Player {playerIndex}: Ammunition manager not assigned!");
}
if (slingshotController == null)
{
Logging.Error($"[AmmunitionPanel] Player {playerIndex}: Slingshot controller not assigned!");
}
if (turnManager == null)
{
Logging.Error($"[AmmunitionPanel] Player {playerIndex}: Turn manager not assigned!");
}
if (ammoButtons == null || ammoButtons.Length == 0)
{
Logging.Warning($"[AmmunitionPanel] Player {playerIndex}: No ammo buttons assigned!");
@@ -78,10 +64,10 @@ namespace Minigames.FortFight.UI
// Initialize ammo buttons with player context
InitializeButtons();
// Subscribe to turn events
if (turnManager != null)
// Subscribe to turn events via singleton
if (TurnManager.Instance != null)
{
turnManager.OnTurnStarted += HandleTurnStarted;
TurnManager.Instance.OnTurnStarted += HandleTurnStarted;
}
// Start hidden
@@ -93,9 +79,9 @@ namespace Minigames.FortFight.UI
base.OnManagedDestroy();
// Unsubscribe from events
if (turnManager != null)
if (TurnManager.Instance != null)
{
turnManager.OnTurnStarted -= HandleTurnStarted;
TurnManager.Instance.OnTurnStarted -= HandleTurnStarted;
}
}
@@ -104,13 +90,13 @@ namespace Minigames.FortFight.UI
/// </summary>
private void InitializeButtons()
{
if (ammunitionManager == null || slingshotController == null || ammoButtons == null)
if (AmmunitionManager.Instance == null || slingshotController == null || ammoButtons == null)
{
return;
}
// Get available projectile types from settings
var availableTypes = ammunitionManager.GetAvailableProjectileTypes();
var availableTypes = AmmunitionManager.Instance.GetAvailableProjectileTypes();
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
if (settings == null)
@@ -126,7 +112,7 @@ namespace Minigames.FortFight.UI
var config = settings.GetProjectileConfig(availableTypes[i]);
if (config != null)
{
ammoButtons[i].Initialize(config, ammunitionManager, slingshotController, playerIndex);
ammoButtons[i].Initialize(config, AmmunitionManager.Instance, slingshotController, playerIndex);
Logging.Debug($"[AmmunitionPanel] Player {playerIndex}: Initialized button for {config.displayName}");
}
}

View File

@@ -31,6 +31,12 @@ namespace Minigames.FortFight.UI
[Tooltip("Leave empty to auto-find")]
[SerializeField] private Core.FortManager fortManager;
[Header("Debug Display")]
[Tooltip("Show numerical HP values (current/max)")]
[SerializeField] private bool debugDisplay = false;
[Tooltip("Text field to display 'current/max' HP values")]
[SerializeField] private TextMeshProUGUI debugHpText;
#endregion
#region Private State
@@ -45,11 +51,17 @@ namespace Minigames.FortFight.UI
{
base.OnManagedStart();
Logging.Debug($"[FortHealthUI] OnManagedStart - autoBindToFort: {autoBindToFort}, isPlayerFort: {isPlayerFort}");
// Auto-bind to dynamically spawned forts
if (autoBindToFort)
{
SetupAutoBinding();
}
else
{
Logging.Warning($"[FortHealthUI] Auto-bind disabled! HP UI will not update.");
}
}
internal override void OnManagedDestroy()
@@ -76,33 +88,53 @@ namespace Minigames.FortFight.UI
private void SetupAutoBinding()
{
// Find FortManager if not assigned
if (fortManager == null)
{
fortManager = FindFirstObjectByType<Core.FortManager>();
}
Logging.Debug($"[FortHealthUI] SetupAutoBinding called for {(isPlayerFort ? "PLAYER" : "ENEMY")} fort");
// Get FortManager via singleton
fortManager = Core.FortManager.Instance;
if (fortManager == null)
{
Logging.Warning($"[FortHealthUI] Cannot auto-bind: FortManager not found. HP UI will not update.");
Logging.Error($"[FortHealthUI] CRITICAL: FortManager.Instance is NULL! HP UI will not work.");
return;
}
// Subscribe to appropriate spawn event
Logging.Debug($"[FortHealthUI] FortManager found. Checking if fort already spawned...");
// Check if fort already spawned (missed the spawn event)
FortController existingFort = isPlayerFort ? fortManager.PlayerFort : fortManager.EnemyFort;
if (existingFort != null)
{
Logging.Debug($"[FortHealthUI] Fort already exists, binding immediately: {existingFort.FortName}");
BindToFort(existingFort);
return;
}
Logging.Debug($"[FortHealthUI] Fort not spawned yet. Subscribing to spawn events...");
// Subscribe to appropriate spawn event for future spawn
if (isPlayerFort)
{
fortManager.OnPlayerFortSpawned += OnFortSpawned;
Logging.Debug($"[FortHealthUI] Subscribed to PLAYER fort spawn");
Logging.Debug($"[FortHealthUI] Subscribed to OnPlayerFortSpawned event");
}
else
{
fortManager.OnEnemyFortSpawned += OnFortSpawned;
Logging.Debug($"[FortHealthUI] Subscribed to ENEMY fort spawn");
Logging.Debug($"[FortHealthUI] Subscribed to OnEnemyFortSpawned event");
}
}
private void OnFortSpawned(FortController fort)
{
Logging.Debug($"[FortHealthUI] 🎯 OnFortSpawned event received! Fort: {fort?.FortName ?? "NULL"}");
if (fort == null)
{
Logging.Error($"[FortHealthUI] Fort is NULL in spawn callback!");
return;
}
BindToFort(fort);
}
@@ -140,7 +172,7 @@ namespace Minigames.FortFight.UI
UpdateDisplay();
Logging.Debug($"[FortHealthUI] Bound to fort: {fort.FortName}");
Logging.Debug($"[FortHealthUI] Bound to fort: {fort.FortName}. Event subscription successful.");
}
#endregion
@@ -149,6 +181,7 @@ namespace Minigames.FortFight.UI
private void OnFortDamaged(float damage, float hpPercentage)
{
Logging.Debug($"[FortHealthUI] OnFortDamaged received! Damage: {damage}, HP%: {hpPercentage:F1}%, Fort: {trackedFort?.FortName}");
UpdateDisplay();
}
@@ -158,20 +191,52 @@ namespace Minigames.FortFight.UI
private void UpdateDisplay()
{
if (trackedFort == null) return;
if (trackedFort == null)
{
Logging.Warning("[FortHealthUI] UpdateDisplay called but trackedFort is null!");
return;
}
float hpPercent = trackedFort.HpPercentage;
Logging.Debug($"[FortHealthUI] UpdateDisplay - Fort: {trackedFort.FortName}, HP: {hpPercent:F1}%");
// Update slider
if (hpSlider != null)
{
hpSlider.value = hpPercent / 100f;
Logging.Debug($"[FortHealthUI] Slider updated to {hpSlider.value:F2}");
}
else
{
Logging.Warning("[FortHealthUI] hpSlider is null!");
}
// Update text
if (hpPercentageText != null)
{
hpPercentageText.text = $"{hpPercent:F0}%";
Logging.Debug($"[FortHealthUI] Text updated to {hpPercentageText.text}");
}
else
{
Logging.Warning("[FortHealthUI] hpPercentageText is null!");
}
// Update debug HP display (current/max)
if (debugHpText != null)
{
if (debugDisplay)
{
debugHpText.gameObject.SetActive(true);
float currentHp = trackedFort.CurrentHp;
float maxHp = trackedFort.MaxHp;
debugHpText.text = $"{currentHp:F0}/{maxHp:F0}";
}
else
{
debugHpText.gameObject.SetActive(false);
}
}
// Update color based on HP

View File

@@ -0,0 +1,234 @@
using Core;
using Core.Lifecycle;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Minigames.FortFight.UI
{
/// <summary>
/// Game Over UI - displays when a fort is defeated.
/// Shows match time, winner, and restart button.
/// </summary>
public class GameOverUI : ManagedBehaviour
{
#region Inspector Properties
[Header("UI References")]
[Tooltip("Root GameObject to show/hide the entire UI")]
[SerializeField] private GameObject rootPanel;
[Tooltip("Text showing elapsed time")]
[SerializeField] private TextMeshProUGUI elapsedTimeText;
[Tooltip("Text showing winner")]
[SerializeField] private TextMeshProUGUI winnerText;
[Tooltip("Restart button")]
[SerializeField] private Button restartButton;
[Header("Optional Visuals")]
[Tooltip("Optional canvas group for fade-in")]
[SerializeField] private CanvasGroup canvasGroup;
#endregion
#region Lifecycle
internal override void OnManagedAwake()
{
base.OnManagedAwake();
// Validate references
if (rootPanel == null)
{
Logging.Error("[GameOverUI] Root panel not assigned!");
}
if (elapsedTimeText == null)
{
Logging.Warning("[GameOverUI] Elapsed time text not assigned!");
}
if (winnerText == null)
{
Logging.Warning("[GameOverUI] Winner text not assigned!");
}
if (restartButton == null)
{
Logging.Error("[GameOverUI] Restart button not assigned!");
}
// Setup button listener
if (restartButton != null)
{
restartButton.onClick.AddListener(OnRestartClicked);
}
// Ensure canvas group exists for fade
if (canvasGroup == null && rootPanel != null)
{
canvasGroup = rootPanel.GetComponent<CanvasGroup>();
}
// Start hidden
Hide();
}
internal override void OnManagedDestroy()
{
base.OnManagedDestroy();
// Remove button listener
if (restartButton != null)
{
restartButton.onClick.RemoveListener(OnRestartClicked);
}
}
#endregion
#region Event Handlers
private void OnRestartClicked()
{
Logging.Debug("[GameOverUI] Restart button clicked, reloading scene...");
RestartGame();
}
#endregion
#region Display
/// <summary>
/// Show the game over UI with match results
/// Called by FortFightGameManager when game ends
/// </summary>
public void Show()
{
if (rootPanel != null)
{
rootPanel.SetActive(true);
}
// Get game manager for elapsed time
var gameManager = Core.FortFightGameManager.Instance;
if (gameManager != null)
{
float elapsedTime = gameManager.ElapsedGameTime;
UpdateElapsedTime(elapsedTime);
// Determine winner
DetermineWinner();
}
// Optional: Fade in
if (canvasGroup != null)
{
canvasGroup.alpha = 0f;
StartCoroutine(FadeIn());
}
Logging.Debug("[GameOverUI] Game over UI shown");
}
/// <summary>
/// Hide the game over UI
/// </summary>
public void Hide()
{
if (rootPanel != null)
{
rootPanel.SetActive(false);
}
}
/// <summary>
/// Update the elapsed time display
/// </summary>
private void UpdateElapsedTime(float seconds)
{
if (elapsedTimeText == null) return;
// Format as MM:SS
int minutes = Mathf.FloorToInt(seconds / 60f);
int secs = Mathf.FloorToInt(seconds % 60f);
elapsedTimeText.text = $"{minutes:00}:{secs:00}";
}
/// <summary>
/// Determine and display the winner
/// </summary>
private void DetermineWinner()
{
if (winnerText == null) return;
var fortManager = Core.FortManager.Instance;
if (fortManager == null) return;
bool playerDefeated = fortManager.PlayerFort?.IsDefeated ?? false;
bool enemyDefeated = fortManager.EnemyFort?.IsDefeated ?? false;
if (playerDefeated && enemyDefeated)
{
winnerText.text = "DRAW!";
}
else if (playerDefeated)
{
winnerText.text = "PLAYER TWO WINS!";
}
else if (enemyDefeated)
{
winnerText.text = "PLAYER ONE WINS!";
}
else
{
winnerText.text = "GAME OVER";
}
}
/// <summary>
/// Fade in the UI over time
/// </summary>
private System.Collections.IEnumerator FadeIn()
{
float duration = 0.5f;
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
if (canvasGroup != null)
{
canvasGroup.alpha = Mathf.Lerp(0f, 1f, elapsed / duration);
}
yield return null;
}
if (canvasGroup != null)
{
canvasGroup.alpha = 1f;
}
}
#endregion
#region Restart
/// <summary>
/// Restart the game by reloading the current scene
/// </summary>
private void RestartGame()
{
// Use Unity's SceneManager to reload current scene
string currentScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
Logging.Debug($"[GameOverUI] Reloading scene: {currentScene}");
UnityEngine.SceneManagement.SceneManager.LoadScene(currentScene);
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ffb13ad5109340eba06f9c02082ece94
timeCreated: 1764806274

View File

@@ -1,6 +1,5 @@
using Core;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UI.Core;
using Minigames.FortFight.Core;
@@ -48,8 +47,8 @@ namespace Minigames.FortFight.UI
{
base.OnManagedStart();
// Get turn manager reference
turnManager = FindFirstObjectByType<TurnManager>();
// Get turn manager reference via singleton
turnManager = TurnManager.Instance;
if (turnManager != null)
{