Stash work
This commit is contained in:
198
Assets/Scripts/Minigames/FortFight/UI/FortHealthUI.cs
Normal file
198
Assets/Scripts/Minigames/FortFight/UI/FortHealthUI.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using Core;
|
||||
using Core.Lifecycle;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
using Minigames.FortFight.Fort;
|
||||
|
||||
namespace Minigames.FortFight.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Displays HP bar and percentage for a fort
|
||||
/// </summary>
|
||||
public class FortHealthUI : ManagedBehaviour
|
||||
{
|
||||
#region Inspector Properties
|
||||
|
||||
[Header("UI References")]
|
||||
[SerializeField] private Slider hpSlider;
|
||||
[SerializeField] private TextMeshProUGUI hpPercentageText;
|
||||
[SerializeField] private TextMeshProUGUI fortNameText;
|
||||
|
||||
[Header("Visual Feedback")]
|
||||
[SerializeField] private Image fillImage;
|
||||
[SerializeField] private Color healthyColor = Color.green;
|
||||
[SerializeField] private Color damagedColor = Color.yellow;
|
||||
[SerializeField] private Color criticalColor = Color.red;
|
||||
|
||||
[Header("Auto-Binding (for Dynamic Spawning)")]
|
||||
[SerializeField] private bool autoBindToFort = true;
|
||||
[SerializeField] private bool isPlayerFort = true;
|
||||
[Tooltip("Leave empty to auto-find")]
|
||||
[SerializeField] private Core.FortManager fortManager;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private State
|
||||
|
||||
private FortController trackedFort;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lifecycle
|
||||
|
||||
internal override void OnManagedStart()
|
||||
{
|
||||
base.OnManagedStart();
|
||||
|
||||
// Auto-bind to dynamically spawned forts
|
||||
if (autoBindToFort)
|
||||
{
|
||||
SetupAutoBinding();
|
||||
}
|
||||
}
|
||||
|
||||
internal override void OnManagedDestroy()
|
||||
{
|
||||
base.OnManagedDestroy();
|
||||
|
||||
// Unsubscribe from fort events
|
||||
if (trackedFort != null)
|
||||
{
|
||||
trackedFort.OnFortDamaged -= OnFortDamaged;
|
||||
}
|
||||
|
||||
// Unsubscribe from fort manager
|
||||
if (fortManager != null)
|
||||
{
|
||||
fortManager.OnPlayerFortSpawned -= OnFortSpawned;
|
||||
fortManager.OnEnemyFortSpawned -= OnFortSpawned;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Auto-Binding
|
||||
|
||||
private void SetupAutoBinding()
|
||||
{
|
||||
// Find FortManager if not assigned
|
||||
if (fortManager == null)
|
||||
{
|
||||
fortManager = FindFirstObjectByType<Core.FortManager>();
|
||||
}
|
||||
|
||||
if (fortManager == null)
|
||||
{
|
||||
Logging.Warning($"[FortHealthUI] Cannot auto-bind: FortManager not found. HP UI will not update.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Subscribe to appropriate spawn event
|
||||
if (isPlayerFort)
|
||||
{
|
||||
fortManager.OnPlayerFortSpawned += OnFortSpawned;
|
||||
Logging.Debug($"[FortHealthUI] Subscribed to PLAYER fort spawn");
|
||||
}
|
||||
else
|
||||
{
|
||||
fortManager.OnEnemyFortSpawned += OnFortSpawned;
|
||||
Logging.Debug($"[FortHealthUI] Subscribed to ENEMY fort spawn");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFortSpawned(FortController fort)
|
||||
{
|
||||
BindToFort(fort);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Setup
|
||||
|
||||
/// <summary>
|
||||
/// Bind this UI to a specific fort
|
||||
/// </summary>
|
||||
public void BindToFort(FortController fort)
|
||||
{
|
||||
if (fort == null)
|
||||
{
|
||||
Logging.Warning("[FortHealthUI] Cannot bind to null fort!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Unsubscribe from previous fort
|
||||
if (trackedFort != null)
|
||||
{
|
||||
trackedFort.OnFortDamaged -= OnFortDamaged;
|
||||
}
|
||||
|
||||
trackedFort = fort;
|
||||
|
||||
// Subscribe to fort events
|
||||
trackedFort.OnFortDamaged += OnFortDamaged;
|
||||
|
||||
// Initialize UI
|
||||
if (fortNameText != null)
|
||||
{
|
||||
fortNameText.text = fort.FortName;
|
||||
}
|
||||
|
||||
UpdateDisplay();
|
||||
|
||||
Logging.Debug($"[FortHealthUI] Bound to fort: {fort.FortName}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
private void OnFortDamaged(float damage, float hpPercentage)
|
||||
{
|
||||
UpdateDisplay();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Display Update
|
||||
|
||||
private void UpdateDisplay()
|
||||
{
|
||||
if (trackedFort == null) return;
|
||||
|
||||
float hpPercent = trackedFort.HpPercentage;
|
||||
|
||||
// Update slider
|
||||
if (hpSlider != null)
|
||||
{
|
||||
hpSlider.value = hpPercent / 100f;
|
||||
}
|
||||
|
||||
// Update text
|
||||
if (hpPercentageText != null)
|
||||
{
|
||||
hpPercentageText.text = $"{hpPercent:F0}%";
|
||||
}
|
||||
|
||||
// Update color based on HP
|
||||
if (fillImage != null)
|
||||
{
|
||||
if (hpPercent > 60f)
|
||||
{
|
||||
fillImage.color = healthyColor;
|
||||
}
|
||||
else if (hpPercent > 30f)
|
||||
{
|
||||
fillImage.color = damagedColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
fillImage.color = criticalColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed9e5253aa2a40c9a9028767466456b1
|
||||
timeCreated: 1764592117
|
||||
266
Assets/Scripts/Minigames/FortFight/UI/GameplayPage.cs
Normal file
266
Assets/Scripts/Minigames/FortFight/UI/GameplayPage.cs
Normal file
@@ -0,0 +1,266 @@
|
||||
using Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
using UI.Core;
|
||||
using Minigames.FortFight.Core;
|
||||
using Minigames.FortFight.Data;
|
||||
using Pixelplacement;
|
||||
|
||||
namespace Minigames.FortFight.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Main gameplay UI page for Fort Fight minigame.
|
||||
/// Displays turn info and allows player to take actions (stubbed for Phase 1).
|
||||
/// </summary>
|
||||
public class GameplayPage : UIPage
|
||||
{
|
||||
[Header("UI Elements")]
|
||||
[SerializeField] private TextMeshProUGUI turnIndicatorText;
|
||||
[SerializeField] private TextMeshProUGUI currentPlayerText;
|
||||
[SerializeField] private Button takeActionButton;
|
||||
[SerializeField] private TextMeshProUGUI actionButtonText;
|
||||
|
||||
[Header("Optional Visual Elements")]
|
||||
[SerializeField] private CanvasGroup canvasGroup;
|
||||
[SerializeField] private GameObject playerActionPanel;
|
||||
[SerializeField] private GameObject aiTurnPanel;
|
||||
|
||||
private TurnManager turnManager;
|
||||
|
||||
#region Initialization
|
||||
|
||||
internal override void OnManagedAwake()
|
||||
{
|
||||
base.OnManagedAwake();
|
||||
|
||||
// Validate references
|
||||
ValidateReferences();
|
||||
|
||||
// Set up button
|
||||
if (takeActionButton != null)
|
||||
{
|
||||
takeActionButton.onClick.AddListener(OnTakeActionClicked);
|
||||
}
|
||||
|
||||
// Set up canvas group
|
||||
if (canvasGroup == null)
|
||||
{
|
||||
canvasGroup = GetComponent<CanvasGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
internal override void OnManagedStart()
|
||||
{
|
||||
base.OnManagedStart();
|
||||
|
||||
// Get turn manager reference
|
||||
turnManager = FindObjectOfType<TurnManager>();
|
||||
|
||||
if (turnManager != null)
|
||||
{
|
||||
turnManager.OnTurnStarted += OnTurnStarted;
|
||||
turnManager.OnTurnEnded += OnTurnEnded;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Error("[GameplayPage] TurnManager not found!");
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateReferences()
|
||||
{
|
||||
if (turnIndicatorText == null)
|
||||
{
|
||||
Logging.Warning("[GameplayPage] Turn indicator text not assigned!");
|
||||
}
|
||||
|
||||
if (currentPlayerText == null)
|
||||
{
|
||||
Logging.Warning("[GameplayPage] Current player text not assigned!");
|
||||
}
|
||||
|
||||
if (takeActionButton == null)
|
||||
{
|
||||
Logging.Error("[GameplayPage] Take action button not assigned!");
|
||||
}
|
||||
|
||||
if (actionButtonText == null)
|
||||
{
|
||||
Logging.Warning("[GameplayPage] Action button text not assigned!");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Turn Events
|
||||
|
||||
/// <summary>
|
||||
/// Called when a new turn starts
|
||||
/// </summary>
|
||||
private void OnTurnStarted(PlayerData currentPlayer, TurnState turnState)
|
||||
{
|
||||
Logging.Debug($"[GameplayPage] Turn started - Player: {currentPlayer.PlayerName}, State: {turnState}");
|
||||
|
||||
UpdateTurnUI(currentPlayer, turnState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the current turn ends
|
||||
/// </summary>
|
||||
private void OnTurnEnded(PlayerData player)
|
||||
{
|
||||
Logging.Debug($"[GameplayPage] Turn ended for {player.PlayerName}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Updates
|
||||
|
||||
/// <summary>
|
||||
/// Update the UI to reflect current turn state
|
||||
/// </summary>
|
||||
private void UpdateTurnUI(PlayerData currentPlayer, TurnState turnState)
|
||||
{
|
||||
// Update turn counter
|
||||
if (turnIndicatorText != null && turnManager != null)
|
||||
{
|
||||
turnIndicatorText.text = $"Turn {turnManager.TurnCount + 1}";
|
||||
}
|
||||
|
||||
// Update current player display
|
||||
if (currentPlayerText != null)
|
||||
{
|
||||
currentPlayerText.text = $"{currentPlayer.PlayerName}'s Turn";
|
||||
}
|
||||
|
||||
// Show/hide appropriate panels based on turn state
|
||||
if (turnState == TurnState.AITurn)
|
||||
{
|
||||
// AI turn - hide player controls
|
||||
if (playerActionPanel != null)
|
||||
{
|
||||
playerActionPanel.SetActive(false);
|
||||
}
|
||||
|
||||
if (aiTurnPanel != null)
|
||||
{
|
||||
aiTurnPanel.SetActive(true);
|
||||
}
|
||||
|
||||
if (takeActionButton != null)
|
||||
{
|
||||
takeActionButton.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
else if (turnState == TurnState.PlayerOneTurn || turnState == TurnState.PlayerTwoTurn)
|
||||
{
|
||||
// Player turn - show controls
|
||||
if (playerActionPanel != null)
|
||||
{
|
||||
playerActionPanel.SetActive(true);
|
||||
}
|
||||
|
||||
if (aiTurnPanel != null)
|
||||
{
|
||||
aiTurnPanel.SetActive(false);
|
||||
}
|
||||
|
||||
if (takeActionButton != null)
|
||||
{
|
||||
takeActionButton.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
if (actionButtonText != null)
|
||||
{
|
||||
actionButtonText.text = "Take Action (Stubbed)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Button Callbacks
|
||||
|
||||
/// <summary>
|
||||
/// Called when player clicks the "Take Action" button
|
||||
/// STUBBED for Phase 1 - just logs and ends turn
|
||||
/// </summary>
|
||||
private void OnTakeActionClicked()
|
||||
{
|
||||
if (turnManager == null)
|
||||
{
|
||||
Logging.Error("[GameplayPage] Cannot take action - TurnManager not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerData currentPlayer = turnManager.CurrentPlayer;
|
||||
|
||||
// STUBBED: Log the action
|
||||
Logging.Debug($"[GameplayPage] {currentPlayer.PlayerName} takes action! (STUBBED - no actual combat yet)");
|
||||
|
||||
// TODO Phase 3: Replace with actual slingshot/shooting interface
|
||||
|
||||
// End the turn
|
||||
turnManager.EndTurn();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Transitions
|
||||
|
||||
protected override void DoTransitionIn(System.Action onComplete)
|
||||
{
|
||||
// Simple fade in if canvas group is available
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
canvasGroup.alpha = 0f;
|
||||
Tween.CanvasGroupAlpha(canvasGroup, 1f, transitionDuration, 0f, Tween.EaseOut,
|
||||
completeCallback: () => onComplete?.Invoke());
|
||||
}
|
||||
else
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DoTransitionOut(System.Action onComplete)
|
||||
{
|
||||
// Simple fade out if canvas group is available
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
Tween.CanvasGroupAlpha(canvasGroup, 0f, transitionDuration, 0f, Tween.EaseIn,
|
||||
completeCallback: () => onComplete?.Invoke());
|
||||
}
|
||||
else
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cleanup
|
||||
|
||||
internal override void OnManagedDestroy()
|
||||
{
|
||||
base.OnManagedDestroy();
|
||||
|
||||
// Unsubscribe from turn manager events
|
||||
if (turnManager != null)
|
||||
{
|
||||
turnManager.OnTurnStarted -= OnTurnStarted;
|
||||
turnManager.OnTurnEnded -= OnTurnEnded;
|
||||
}
|
||||
|
||||
// Unsubscribe from button
|
||||
if (takeActionButton != null)
|
||||
{
|
||||
takeActionButton.onClick.RemoveListener(OnTakeActionClicked);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e22e2729514a5ee40bb2d4c23fbeb75f
|
||||
150
Assets/Scripts/Minigames/FortFight/UI/ModeSelectionPage.cs
Normal file
150
Assets/Scripts/Minigames/FortFight/UI/ModeSelectionPage.cs
Normal file
@@ -0,0 +1,150 @@
|
||||
using Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UI.Core;
|
||||
using Minigames.FortFight.Core;
|
||||
using Minigames.FortFight.Data;
|
||||
using Pixelplacement;
|
||||
|
||||
namespace Minigames.FortFight.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// UI page for selecting single-player or two-player mode
|
||||
/// </summary>
|
||||
public class ModeSelectionPage : UIPage
|
||||
{
|
||||
[Header("Mode Selection Buttons")]
|
||||
[SerializeField] private Button singlePlayerButton;
|
||||
[SerializeField] private Button twoPlayerButton;
|
||||
|
||||
[Header("Optional Visual Elements")]
|
||||
[SerializeField] private GameObject titleText;
|
||||
[SerializeField] private CanvasGroup canvasGroup;
|
||||
|
||||
#region Initialization
|
||||
|
||||
internal override void OnManagedAwake()
|
||||
{
|
||||
base.OnManagedAwake();
|
||||
|
||||
// Validate button references
|
||||
if (singlePlayerButton == null)
|
||||
{
|
||||
Logging.Error("[ModeSelectionPage] Single player button not assigned!");
|
||||
}
|
||||
else
|
||||
{
|
||||
singlePlayerButton.onClick.AddListener(OnSinglePlayerSelected);
|
||||
}
|
||||
|
||||
if (twoPlayerButton == null)
|
||||
{
|
||||
Logging.Error("[ModeSelectionPage] Two player button not assigned!");
|
||||
}
|
||||
else
|
||||
{
|
||||
twoPlayerButton.onClick.AddListener(OnTwoPlayerSelected);
|
||||
}
|
||||
|
||||
// Set up canvas group if available
|
||||
if (canvasGroup == null)
|
||||
{
|
||||
canvasGroup = GetComponent<CanvasGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Button Callbacks
|
||||
|
||||
/// <summary>
|
||||
/// Called when single player button is clicked
|
||||
/// </summary>
|
||||
private void OnSinglePlayerSelected()
|
||||
{
|
||||
Logging.Debug("[ModeSelectionPage] Single player mode selected");
|
||||
|
||||
if (FortFightGameManager.Instance != null)
|
||||
{
|
||||
FortFightGameManager.Instance.SelectGameMode(FortFightGameMode.SinglePlayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Error("[ModeSelectionPage] FortFightGameManager instance not found!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when two player button is clicked
|
||||
/// </summary>
|
||||
private void OnTwoPlayerSelected()
|
||||
{
|
||||
Logging.Debug("[ModeSelectionPage] Two player mode selected");
|
||||
|
||||
if (FortFightGameManager.Instance != null)
|
||||
{
|
||||
FortFightGameManager.Instance.SelectGameMode(FortFightGameMode.TwoPlayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Error("[ModeSelectionPage] FortFightGameManager instance not found!");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Transitions
|
||||
|
||||
protected override void DoTransitionIn(System.Action onComplete)
|
||||
{
|
||||
// Simple fade in if canvas group is available
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
canvasGroup.alpha = 0f;
|
||||
Tween.CanvasGroupAlpha(canvasGroup, 1f, transitionDuration, 0f, Tween.EaseOut,
|
||||
completeCallback: () => onComplete?.Invoke());
|
||||
}
|
||||
else
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DoTransitionOut(System.Action onComplete)
|
||||
{
|
||||
// Simple fade out if canvas group is available
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
Tween.CanvasGroupAlpha(canvasGroup, 0f, transitionDuration, 0f, Tween.EaseIn,
|
||||
completeCallback: () => onComplete?.Invoke());
|
||||
}
|
||||
else
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cleanup
|
||||
|
||||
internal override void OnManagedDestroy()
|
||||
{
|
||||
base.OnManagedDestroy();
|
||||
|
||||
// Unsubscribe from button events
|
||||
if (singlePlayerButton != null)
|
||||
{
|
||||
singlePlayerButton.onClick.RemoveListener(OnSinglePlayerSelected);
|
||||
}
|
||||
|
||||
if (twoPlayerButton != null)
|
||||
{
|
||||
twoPlayerButton.onClick.RemoveListener(OnTwoPlayerSelected);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c1ab5687204db54eaa4ea7f812b3c06
|
||||
Reference in New Issue
Block a user