MazeGraph.cs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. namespace MazeGen
  4. {
  5. /// <summary>
  6. /// The full set of generated rooms so far, plus O(1)-ish id lookup, spatial queries and
  7. /// exit-usage bookkeeping. Everything else (agent tracking, visualization, collision/merge
  8. /// logic) reads from here instead of walking the scene hierarchy.
  9. /// </summary>
  10. public class MazeGraph
  11. {
  12. public readonly Dictionary<int, Room> Rooms = new Dictionary<int, Room>();
  13. public readonly List<Room> StartRooms = new List<Room>();
  14. public readonly List<Room> ExitRooms = new List<Room>();
  15. private readonly SpatialRoomIndex _spatialIndex;
  16. private int _nextRoomId;
  17. private int _nextExitId;
  18. public int RoomCount => Rooms.Count;
  19. /// <summary>
  20. /// Total exits across the whole graph that are not yet used. This must never be
  21. /// allowed to reach 0 while ExitRooms.Count == 0 - if it did, the maze would have no
  22. /// remaining way to grow and could never produce a reachable exit.
  23. /// </summary>
  24. public int UnusedExitCount { get; private set; }
  25. public MazeGraph(float spatialCellSize)
  26. {
  27. _spatialIndex = new SpatialRoomIndex(spatialCellSize);
  28. }
  29. public int AllocateRoomId() => _nextRoomId++;
  30. public int AllocateExitId() => _nextExitId++;
  31. public void Register(Room room)
  32. {
  33. Rooms[room.Id] = room;
  34. if (room.Kind == RoomKind.Start) StartRooms.Add(room);
  35. if (room.Kind == RoomKind.Exit) ExitRooms.Add(room);
  36. _spatialIndex.Add(room);
  37. }
  38. public Room Get(int id) => Rooms.TryGetValue(id, out var room) ? room : null;
  39. public IEnumerable<Room> QueryRoomsNear(Vector2 position, float radius) =>
  40. _spatialIndex.QueryNearby(position, radius);
  41. /// <summary>Adds an exit to a room and keeps the unused-exit counter in sync.</summary>
  42. public void AddExit(Room room, Exit exit)
  43. {
  44. room.Exits.Add(exit);
  45. if (!exit.IsUsed) UnusedExitCount++;
  46. }
  47. /// <summary>Marks an exit as used (idempotent) and keeps the unused-exit counter in sync.</summary>
  48. public void MarkExitUsed(Exit exit)
  49. {
  50. if (exit.IsUsed) return;
  51. exit.IsUsed = true;
  52. UnusedExitCount--;
  53. }
  54. /// <summary>
  55. /// Undoes a speculative AddExit for an exit that turned out to be unusable (e.g. a
  56. /// door added on-the-fly to close a loop, where the path to it was later found to be
  57. /// blocked). Only valid for still-unused exits.
  58. /// </summary>
  59. public void RemoveUnusedExit(Room room, Exit exit)
  60. {
  61. if (exit.IsUsed) return;
  62. if (room.Exits.Remove(exit)) UnusedExitCount--;
  63. }
  64. }
  65. }