// Assets/_Project/Scripts/Gameplay/SelectionState.cs using UnityEngine; namespace TD.Gameplay { /// /// Minimal scene-local selection state. Holds a reference to whichever /// the local player has selected, fires an event when /// the selection changes, and exposes a query for "is this builder selected /// right now?". /// /// /// Scope. D2 only needs this for: "Escape with builder selected /// cancels its queue", and "right-click with builder selected and queue /// established cancels the queue (the right-click is consumed by selection /// instead of issuing a move)". A full selection system that supports world /// highlighting, multi-select, and HUD context panels is deferred to the HUD /// path. /// /// Local-only. Selection is a UI concept, not a gameplay one. /// Other clients have no business knowing whether you've selected your own /// builder. The component is a plain MonoBehaviour and lives in the scene /// alongside other client-side controllers. /// /// Singleton. One per scene, accessed via . /// The selection consumer (BuilderInputController) and the selection driver /// (mouse-click raycast) both go through this single source of truth. /// public class SelectionState : MonoBehaviour { // ----- Singleton -------------------------------------------------- /// /// The active SelectionState. Null before the scene loads. Always null-check. /// 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 Builder selectedBuilder; /// The currently selected builder, or null if nothing is selected. public Builder SelectedBuilder => selectedBuilder; /// True if any builder is currently selected. public bool HasSelection => selectedBuilder != null; /// True if is the currently selected builder. public bool IsSelected(Builder b) => b != null && selectedBuilder == 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 builder. Pass null to clear. /// Fires only if the selection actually changes. /// public void Select(Builder builder) { if (selectedBuilder == builder) return; selectedBuilder = builder; OnSelectionChanged?.Invoke(selectedBuilder); } /// Clears the selection. Equivalent to Select(null). public void Clear() => Select(null); } }