// Assets/_Project/Scripts/UI/Minimap/MinimapEntityRegistry.cs using System; using System.Collections.Generic; using UnityEngine; namespace TD.UI.Minimap { /// /// Visual category for a minimap entity. Determines the shape and size of the icon drawn /// by . Color is supplied separately by the entity itself so the /// view does not need to know about ownership / faction mapping. /// public enum MinimapIconKind : byte { Enemy, Tower, Builder, } /// /// 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). /// public interface IMinimapEntity { Vector3 WorldPosition { get; } Color MinimapColor { get; } MinimapIconKind IconKind { get; } /// /// 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. /// float MinimapWorldSize { get; } } /// /// Static registry of every entity currently visible on the minimap. Entities register /// themselves on spawn and deregister on despawn; the iterates the /// set on each refresh. /// /// /// Backing store is a so duplicate Register calls are no-ops and /// Deregister is O(1). Iteration uses the struct enumerator via to /// avoid the boxing that would happen if we exposed an . /// /// Static lifetime is intentional: the registry survives scene transitions only if entities /// remember to deregister. NGO's OnNetworkDespawn covers that for towers / builders / /// enemies. Manual is provided for tests and for explicit reset on match /// teardown if needed. /// public static class MinimapEntityRegistry { private static readonly HashSet s_entities = new HashSet(); /// Number of currently-registered entities. Cheap, no allocation. public static int Count => s_entities.Count; /// /// Registers for minimap rendering. No-op if already registered. /// Safe to call from any thread that Unity allows (i.e., the main thread). /// public static void Register(IMinimapEntity entity) { if (entity == null) return; s_entities.Add(entity); } /// Removes from the registry. No-op if not present. public static void Deregister(IMinimapEntity entity) { if (entity == null) return; s_entities.Remove(entity); } /// /// Invokes once per registered entity. Uses HashSet's struct /// enumerator so iteration is allocation-free (the only allocation is the closure that /// may carry, which is the caller's choice). /// public static void ForEach(Action action) { if (action == null) return; foreach (var e in s_entities) action(e); } /// Drops every registered entity. Tests and explicit match-teardown use only. public static void Clear() => s_entities.Clear(); } }