From 8d56feee807c525ccf34f91e972cbdb2d50f52cf Mon Sep 17 00:00:00 2001 From: KoalaTrapLord <265133236+KoalaTrapLord@users.noreply.github.com> Date: Sat, 28 Mar 2026 19:55:17 -0400 Subject: [PATCH] feat(#140): add PhaseTrackerWidget and PhaseStepButton --- .../UI/Battleground/PhaseStepButton.cs | 31 +++++++ .../UI/Battleground/PhaseTrackerWidget.cs | 80 +++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 unity-client/Assets/Scripts/UI/Battleground/PhaseStepButton.cs create mode 100644 unity-client/Assets/Scripts/UI/Battleground/PhaseTrackerWidget.cs diff --git a/unity-client/Assets/Scripts/UI/Battleground/PhaseStepButton.cs b/unity-client/Assets/Scripts/UI/Battleground/PhaseStepButton.cs new file mode 100644 index 0000000..851ca40 --- /dev/null +++ b/unity-client/Assets/Scripts/UI/Battleground/PhaseStepButton.cs @@ -0,0 +1,31 @@ +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +namespace CommanderAILab.UI +{ + /// + /// A single phase pill in the PhaseTrackerWidget strip. + /// Changes color, font weight, and scale when activated. + /// + public class PhaseStepButton : MonoBehaviour + { + [SerializeField] private Image background; + [SerializeField] private TMP_Text label; + + [Header("Colors")] + [SerializeField] private Color activeColor = new Color(1f, 0.85f, 0f); // amber/yellow + [SerializeField] private Color inactiveColor = new Color(0.2f, 0.2f, 0.2f); // dark grey + + private Vector3 _baseScale; + + private void Awake() => _baseScale = transform.localScale; + + public void SetActive(bool active) + { + if (background) background.color = active ? activeColor : inactiveColor; + if (label) label.fontStyle = active ? TMPro.FontStyles.Bold : TMPro.FontStyles.Normal; + transform.localScale = active ? _baseScale * 1.1f : _baseScale; + } + } +} diff --git a/unity-client/Assets/Scripts/UI/Battleground/PhaseTrackerWidget.cs b/unity-client/Assets/Scripts/UI/Battleground/PhaseTrackerWidget.cs new file mode 100644 index 0000000..304bfab --- /dev/null +++ b/unity-client/Assets/Scripts/UI/Battleground/PhaseTrackerWidget.cs @@ -0,0 +1,80 @@ +using UnityEngine; +using TMPro; + +namespace CommanderAILab.UI +{ + /// + /// Horizontal strip of 13 phase/step buttons in the BattlefieldCenter panel. + /// Subscribes to GameStateManager.OnPhaseChanged. + /// Test without backend: press Space in Play Mode (debug binding below). + /// + public class PhaseTrackerWidget : MonoBehaviour + { + public enum Phase + { + Untap = 0, + Upkeep, + Draw, + Main1, + BeginCombat, + DeclareAttackers, + DeclareBlockers, + FirstStrikeDamage, + Damage, + EndCombat, + Main2, + EndStep, + Cleanup + } + + [SerializeField] private PhaseStepButton[] stepButtons; // 13 buttons, one per Phase + [SerializeField] private TMP_Text activePlayerLabel; + [SerializeField] private TMP_Text turnNumberLabel; + + private Phase _currentPhase; + + // ── Lifecycle ─────────────────────────────────────────── + private void Start() + { + if (GameStateManager.Instance != null) + GameStateManager.Instance.OnPhaseChanged += SetPhase; + + SetPhase(Phase.Untap, 0, 1); + } + + private void OnDestroy() + { + if (GameStateManager.Instance != null) + GameStateManager.Instance.OnPhaseChanged -= SetPhase; + } + + // ── Public API ───────────────────────────────────────── + public void SetPhase(Phase phase, int seatIndex, int turnNumber) + { + _currentPhase = phase; + + for (int i = 0; i < stepButtons.Length; i++) + stepButtons[i]?.SetActive(i == (int)phase); + + if (activePlayerLabel) + activePlayerLabel.text = seatIndex == 0 ? "Your Turn" : $"Seat {seatIndex}'s Turn"; + + if (turnNumberLabel) + turnNumberLabel.text = $"Turn {turnNumber}"; + } + + public Phase CurrentPhase => _currentPhase; + + // ── Debug (editor only) ────────────────────────────────── +#if UNITY_EDITOR + private void Update() + { + if (Input.GetKeyDown(KeyCode.Space)) + { + int next = ((int)_currentPhase + 1) % System.Enum.GetValues(typeof(Phase)).Length; + SetPhase((Phase)next, 0, GameStateManager.Instance?.TurnNumber ?? 1); + } + } +#endif + } +}