// Assets/_Project/Scripts/Gameplay/SelectionState.cs using UnityEngine; namespace TD.Gameplay { /// /// Scene-local selection state. Holds a single (the /// builder, a tower, or any future selectable type) and fires /// when it changes. /// /// /// Local-only. Selection is a UI concept — other clients have no /// business knowing whether you've selected something. The component is a plain /// MonoBehaviour and lives in the scene alongside other client-side controllers. /// /// Singleton. One per scene, accessed via . /// Selection drivers (input controller, minimap) and selection consumers /// (HUD, selection-ring visuals) all go through this single source of truth. /// /// Builder convenience. returns the /// current selection cast to Builder (or null if non-builder). Lets the input /// controller and minimap keep the "is the local builder selected?" check /// short without re-type-testing. /// public class SelectionState : MonoBehaviour { // ----- Singleton -------------------------------------------------- public static SelectionState Instance { get; private set; } private void Awake() { if (Instance != null && Instance != this) { Debug.LogWarning("[SelectionState] Multiple instances detected. " + "Only one SelectionState should exist per scene."); } Instance = this; } private void OnDestroy() { if (Instance == this) Instance = null; } // ----- Selection state -------------------------------------------- private ISelectable selected; /// The currently selected object, or null if nothing is selected. public ISelectable SelectedObject => selected; /// Convenience: the selected object if it's a Builder, else null. public Builder SelectedBuilder => selected as Builder; /// True if any object is currently selected. public bool HasSelection => selected != null; /// True if is the currently selected object. public bool IsSelected(ISelectable s) => s != null && (object)selected == (object)s; /// Builder overload — same semantics as . public bool IsSelected(Builder b) => b != null && (object)selected == (object)b; // ----- Events ----------------------------------------------------- /// /// Fired when the selection changes. Argument is the new selection (may be null). /// Subscribe to drive selection-aware UI: highlights, context panels, hotkey hints. /// public event System.Action OnSelectionChanged; // ----- Mutators --------------------------------------------------- /// /// Sets the selected object. Pass null to clear. /// Fires only if the selection actually changes. /// public void Select(ISelectable s) { if ((object)selected == (object)s) return; selected = s; OnSelectionChanged?.Invoke(selected); } /// Clears the selection. Equivalent to Select(null). public void Clear() => Select((ISelectable)null); } }