90 lines
3.7 KiB
C#
90 lines
3.7 KiB
C#
// Assets/_Project/Scripts/Gameplay/SelectionState.cs
|
|
using UnityEngine;
|
|
|
|
namespace TD.Gameplay
|
|
{
|
|
/// <summary>
|
|
/// Minimal scene-local selection state. Holds a reference to whichever
|
|
/// <see cref="Builder"/> the local player has selected, fires an event when
|
|
/// the selection changes, and exposes a query for "is this builder selected
|
|
/// right now?".
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para><b>Scope.</b> 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.</para>
|
|
///
|
|
/// <para><b>Local-only.</b> 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.</para>
|
|
///
|
|
/// <para><b>Singleton.</b> One per scene, accessed via <see cref="Instance"/>.
|
|
/// The selection consumer (BuilderInputController) and the selection driver
|
|
/// (mouse-click raycast) both go through this single source of truth.</para>
|
|
/// </remarks>
|
|
public class SelectionState : MonoBehaviour
|
|
{
|
|
// ----- Singleton --------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// The active SelectionState. Null before the scene loads. Always null-check.
|
|
/// </summary>
|
|
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;
|
|
|
|
/// <summary>The currently selected builder, or null if nothing is selected.</summary>
|
|
public Builder SelectedBuilder => selectedBuilder;
|
|
|
|
/// <summary>True if any builder is currently selected.</summary>
|
|
public bool HasSelection => selectedBuilder != null;
|
|
|
|
/// <summary>True if <paramref name="b"/> is the currently selected builder.</summary>
|
|
public bool IsSelected(Builder b) => b != null && selectedBuilder == b;
|
|
|
|
// ----- Events -----------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Fired when the selection changes. Argument is the new selection (may be null).
|
|
/// Subscribe to drive selection-aware UI: highlights, context panels, hotkey hints.
|
|
/// </summary>
|
|
public event System.Action<Builder> OnSelectionChanged;
|
|
|
|
// ----- Mutators ---------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Sets the selected builder. Pass null to clear.
|
|
/// Fires <see cref="OnSelectionChanged"/> only if the selection actually changes.
|
|
/// </summary>
|
|
public void Select(Builder builder)
|
|
{
|
|
if (selectedBuilder == builder) return;
|
|
selectedBuilder = builder;
|
|
OnSelectionChanged?.Invoke(selectedBuilder);
|
|
}
|
|
|
|
/// <summary>Clears the selection. Equivalent to Select(null).</summary>
|
|
public void Clear() => Select(null);
|
|
}
|
|
}
|