UnityTowerDefense/Assets/_Project/Scripts/UI/Minimap/MinimapEntityRegistry.cs
2026-05-10 22:26:55 -07:00

94 lines
4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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();
}
}