SpatialRoomIndex.cs 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. namespace MazeGen
  4. {
  5. /// <summary>
  6. /// Uniform grid bucket index over Room positions, so "which rooms are near this point"
  7. /// stays cheap even once the maze has thousands of rooms, instead of scanning all of them.
  8. /// </summary>
  9. public class SpatialRoomIndex
  10. {
  11. private readonly float _cellSize;
  12. private readonly Dictionary<(int x, int y), List<Room>> _cells = new Dictionary<(int, int), List<Room>>();
  13. public SpatialRoomIndex(float cellSize)
  14. {
  15. _cellSize = Mathf.Max(cellSize, 0.01f);
  16. }
  17. private (int, int) CellOf(Vector2 position) =>
  18. (Mathf.FloorToInt(position.x / _cellSize), Mathf.FloorToInt(position.y / _cellSize));
  19. public void Add(Room room)
  20. {
  21. var cell = CellOf(room.Position);
  22. if (!_cells.TryGetValue(cell, out var list))
  23. {
  24. list = new List<Room>();
  25. _cells[cell] = list;
  26. }
  27. list.Add(room);
  28. }
  29. /// <summary>
  30. /// Yields every registered room whose bucket falls within `radius` of `position`.
  31. /// This is a broad-phase filter - callers still need an exact distance check.
  32. /// </summary>
  33. public IEnumerable<Room> QueryNearby(Vector2 position, float radius)
  34. {
  35. var (cx, cy) = CellOf(position);
  36. int cellRadius = Mathf.CeilToInt(radius / _cellSize) + 1;
  37. for (int dx = -cellRadius; dx <= cellRadius; dx++)
  38. {
  39. for (int dy = -cellRadius; dy <= cellRadius; dy++)
  40. {
  41. if (_cells.TryGetValue((cx + dx, cy + dy), out var list))
  42. {
  43. foreach (var room in list)
  44. yield return room;
  45. }
  46. }
  47. }
  48. }
  49. }
  50. }