chunk 1: core gameplay scripts scenes runtime assets
This commit is contained in:
89
Assets/Scripts/Core/EntityRegistry.cs
Normal file
89
Assets/Scripts/Core/EntityRegistry.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// EntityRegistry — Zero-allocation replacement for FindObjectsOfType.
|
||||
/// Each MonoBehaviour type auto-registers in OnEnable/OnDisable via EntityRegistryMember<T>.
|
||||
/// Access all instances via EntityRegistry<T>.All (read-only list, no allocation).
|
||||
///
|
||||
/// Usage:
|
||||
/// 1) Add EntityRegistryMember<CashBag> component, or
|
||||
/// 2) Call EntityRegistry<CashBag>.Register(this) in OnEnable / Unregister in OnDisable
|
||||
/// 3) Query: foreach (var bag in EntityRegistry<CashBag>.All) { ... }
|
||||
/// </summary>
|
||||
public static class EntityRegistry<T> where T : class
|
||||
{
|
||||
private static readonly List<T> _instances = new List<T>(32);
|
||||
private static readonly List<T> _readOnly = _instances; // Same ref, cast prevents mutation at call sites
|
||||
|
||||
/// <summary>All currently active instances. Do NOT modify this list.</summary>
|
||||
public static List<T> All => _readOnly;
|
||||
|
||||
/// <summary>Alias for All — convenience method matching GetAll() convention.</summary>
|
||||
public static List<T> GetAll() => _readOnly;
|
||||
|
||||
/// <summary>Number of active instances.</summary>
|
||||
public static int Count => _instances.Count;
|
||||
|
||||
public static void Register(T instance)
|
||||
{
|
||||
if (instance != null && !_instances.Contains(instance))
|
||||
_instances.Add(instance);
|
||||
}
|
||||
|
||||
public static void Unregister(T instance)
|
||||
{
|
||||
_instances.Remove(instance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find nearest instance to a world position.
|
||||
/// Returns null if no instances. O(n) but n is small (≤10 for bags/characters).
|
||||
/// </summary>
|
||||
public static T FindNearest(Vector3 position, System.Func<T, Vector3> getPosition, System.Func<T, bool> filter = null)
|
||||
{
|
||||
T nearest = null;
|
||||
float nearestSqrDist = float.MaxValue;
|
||||
|
||||
for (int i = 0; i < _instances.Count; i++)
|
||||
{
|
||||
T instance = _instances[i];
|
||||
if (instance == null) continue;
|
||||
if (filter != null && !filter(instance)) continue;
|
||||
|
||||
float sqrDist = (getPosition(instance) - position).sqrMagnitude;
|
||||
if (sqrDist < nearestSqrDist)
|
||||
{
|
||||
nearestSqrDist = sqrDist;
|
||||
nearest = instance;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all instances within radius. Uses pre-allocated result list to avoid allocation.
|
||||
/// Caller should process results immediately (list is reused).
|
||||
/// </summary>
|
||||
private static readonly List<T> _withinRadiusResults = new List<T>(16);
|
||||
public static List<T> FindWithinRadius(Vector3 position, float radius, System.Func<T, Vector3> getPosition, System.Func<T, bool> filter = null)
|
||||
{
|
||||
_withinRadiusResults.Clear();
|
||||
float sqrRadius = radius * radius;
|
||||
|
||||
for (int i = 0; i < _instances.Count; i++)
|
||||
{
|
||||
T instance = _instances[i];
|
||||
if (instance == null) continue;
|
||||
if (filter != null && !filter(instance)) continue;
|
||||
|
||||
float sqrDist = (getPosition(instance) - position).sqrMagnitude;
|
||||
if (sqrDist <= sqrRadius)
|
||||
_withinRadiusResults.Add(instance);
|
||||
}
|
||||
return _withinRadiusResults;
|
||||
}
|
||||
|
||||
/// <summary>Call on scene unload to prevent stale references.</summary>
|
||||
public static void Clear() => _instances.Clear();
|
||||
}
|
||||
Reference in New Issue
Block a user