94 lines
4 KiB
C#
94 lines
4 KiB
C#
// Assets/_Project/Scripts/UI/Minimap/MinimapEntityRegistry.cs
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace TD.UI.Minimap
|
||
{
|
||
/// <summary>
|
||
/// Visual category for a minimap entity. Determines the shape and size of the icon drawn
|
||
/// by <see cref="MinimapView"/>. Color is supplied separately by the entity itself so the
|
||
/// view does not need to know about ownership / faction mapping.
|
||
/// </summary>
|
||
public enum MinimapIconKind : byte
|
||
{
|
||
Enemy,
|
||
Tower,
|
||
Builder,
|
||
}
|
||
|
||
/// <summary>
|
||
/// Anything that wants to appear on the minimap as a dynamic icon implements this. The view
|
||
/// reads every getter on each refresh tick, so values may change between reads (movement is
|
||
/// fine — no caching needed).
|
||
/// </summary>
|
||
public interface IMinimapEntity
|
||
{
|
||
Vector3 WorldPosition { get; }
|
||
Color MinimapColor { get; }
|
||
MinimapIconKind IconKind { get; }
|
||
|
||
/// <summary>
|
||
/// The entity's diameter (or footprint extent) in world units. The view converts this
|
||
/// to pixels using the current minimap zoom, so a 2×2 tower will appear as a 2-tile
|
||
/// square on the minimap and adjacent towers will visually touch — matching their
|
||
/// world-space relationship. For point-like entities (builders, enemies) the view
|
||
/// also enforces a minimum pixel size so they stay visible when fully zoomed out.
|
||
/// </summary>
|
||
float MinimapWorldSize { get; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// Static registry of every entity currently visible on the minimap. Entities register
|
||
/// themselves on spawn and deregister on despawn; the <see cref="MinimapView"/> iterates the
|
||
/// set on each refresh.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// Backing store is a <see cref="HashSet{T}"/> so duplicate Register calls are no-ops and
|
||
/// Deregister is O(1). Iteration uses the struct enumerator via <see cref="ForEach"/> to
|
||
/// avoid the boxing that would happen if we exposed an <see cref="IEnumerable{T}"/>.
|
||
///
|
||
/// Static lifetime is intentional: the registry survives scene transitions only if entities
|
||
/// remember to deregister. NGO's <c>OnNetworkDespawn</c> covers that for towers / builders /
|
||
/// enemies. Manual <see cref="Clear"/> is provided for tests and for explicit reset on match
|
||
/// teardown if needed.
|
||
/// </remarks>
|
||
public static class MinimapEntityRegistry
|
||
{
|
||
private static readonly HashSet<IMinimapEntity> s_entities = new HashSet<IMinimapEntity>();
|
||
|
||
/// <summary>Number of currently-registered entities. Cheap, no allocation.</summary>
|
||
public static int Count => s_entities.Count;
|
||
|
||
/// <summary>
|
||
/// Registers <paramref name="entity"/> for minimap rendering. No-op if already registered.
|
||
/// Safe to call from any thread that Unity allows (i.e., the main thread).
|
||
/// </summary>
|
||
public static void Register(IMinimapEntity entity)
|
||
{
|
||
if (entity == null) return;
|
||
s_entities.Add(entity);
|
||
}
|
||
|
||
/// <summary>Removes <paramref name="entity"/> from the registry. No-op if not present.</summary>
|
||
public static void Deregister(IMinimapEntity entity)
|
||
{
|
||
if (entity == null) return;
|
||
s_entities.Remove(entity);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Invokes <paramref name="action"/> once per registered entity. Uses HashSet's struct
|
||
/// enumerator so iteration is allocation-free (the only allocation is the closure that
|
||
/// <paramref name="action"/> may carry, which is the caller's choice).
|
||
/// </summary>
|
||
public static void ForEach(Action<IMinimapEntity> action)
|
||
{
|
||
if (action == null) return;
|
||
foreach (var e in s_entities) action(e);
|
||
}
|
||
|
||
/// <summary>Drops every registered entity. Tests and explicit match-teardown use only.</summary>
|
||
public static void Clear() => s_entities.Clear();
|
||
}
|
||
}
|