Major updates to the HUD and selectable objects
This commit is contained in:
parent
5bc757b385
commit
c100db52e5
23 changed files with 1615 additions and 614 deletions
|
|
@ -4,35 +4,28 @@ 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?".
|
||||
/// Scene-local selection state. Holds a single <see cref="ISelectable"/> (the
|
||||
/// builder, a tower, or any future selectable type) and fires
|
||||
/// <see cref="OnSelectionChanged"/> when it changes.
|
||||
/// </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>Local-only.</b> 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.</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>
|
||||
/// Selection drivers (input controller, minimap) and selection consumers
|
||||
/// (HUD, selection-ring visuals) all go through this single source of truth.</para>
|
||||
///
|
||||
/// <para><b>Builder convenience.</b> <see cref="SelectedBuilder"/> 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.</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()
|
||||
|
|
@ -52,16 +45,22 @@ namespace TD.Gameplay
|
|||
|
||||
// ----- Selection state --------------------------------------------
|
||||
|
||||
private Builder selectedBuilder;
|
||||
private ISelectable selected;
|
||||
|
||||
/// <summary>The currently selected builder, or null if nothing is selected.</summary>
|
||||
public Builder SelectedBuilder => selectedBuilder;
|
||||
/// <summary>The currently selected object, or null if nothing is selected.</summary>
|
||||
public ISelectable SelectedObject => selected;
|
||||
|
||||
/// <summary>True if any builder is currently selected.</summary>
|
||||
public bool HasSelection => selectedBuilder != null;
|
||||
/// <summary>Convenience: the selected object if it's a Builder, else null.</summary>
|
||||
public Builder SelectedBuilder => selected as Builder;
|
||||
|
||||
/// <summary>True if <paramref name="b"/> is the currently selected builder.</summary>
|
||||
public bool IsSelected(Builder b) => b != null && selectedBuilder == b;
|
||||
/// <summary>True if any object is currently selected.</summary>
|
||||
public bool HasSelection => selected != null;
|
||||
|
||||
/// <summary>True if <paramref name="s"/> is the currently selected object.</summary>
|
||||
public bool IsSelected(ISelectable s) => s != null && (object)selected == (object)s;
|
||||
|
||||
/// <summary>Builder overload — same semantics as <see cref="IsSelected(ISelectable)"/>.</summary>
|
||||
public bool IsSelected(Builder b) => b != null && (object)selected == (object)b;
|
||||
|
||||
// ----- Events -----------------------------------------------------
|
||||
|
||||
|
|
@ -69,22 +68,22 @@ namespace TD.Gameplay
|
|||
/// 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;
|
||||
public event System.Action<ISelectable> OnSelectionChanged;
|
||||
|
||||
// ----- Mutators ---------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Sets the selected builder. Pass null to clear.
|
||||
/// Sets the selected object. Pass null to clear.
|
||||
/// Fires <see cref="OnSelectionChanged"/> only if the selection actually changes.
|
||||
/// </summary>
|
||||
public void Select(Builder builder)
|
||||
public void Select(ISelectable s)
|
||||
{
|
||||
if (selectedBuilder == builder) return;
|
||||
selectedBuilder = builder;
|
||||
OnSelectionChanged?.Invoke(selectedBuilder);
|
||||
if ((object)selected == (object)s) return;
|
||||
selected = s;
|
||||
OnSelectionChanged?.Invoke(selected);
|
||||
}
|
||||
|
||||
/// <summary>Clears the selection. Equivalent to Select(null).</summary>
|
||||
public void Clear() => Select(null);
|
||||
public void Clear() => Select((ISelectable)null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue