Grid2D.cs 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // Grid2D from uMMORPG: get/set values of type T at any point
  2. // -> not named 'Grid' because Unity already has a Grid type. causes warnings.
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. namespace Mirror
  6. {
  7. public class Grid2D<T>
  8. {
  9. // the grid
  10. // note that we never remove old keys.
  11. // => over time, HashSet<T>s will be allocated for every possible
  12. // grid position in the world
  13. // => Clear() doesn't clear them so we don't constantly reallocate the
  14. // entries when populating the grid in every Update() call
  15. // => makes the code a lot easier too
  16. // => this is FINE because in the worst case, every grid position in the
  17. // game world is filled with a player anyway!
  18. Dictionary<Vector2Int, HashSet<T>> grid = new Dictionary<Vector2Int, HashSet<T>>();
  19. // cache a 9 neighbor grid of vector2 offsets so we can use them more easily
  20. Vector2Int[] neighbourOffsets =
  21. {
  22. Vector2Int.up,
  23. Vector2Int.up + Vector2Int.left,
  24. Vector2Int.up + Vector2Int.right,
  25. Vector2Int.left,
  26. Vector2Int.zero,
  27. Vector2Int.right,
  28. Vector2Int.down,
  29. Vector2Int.down + Vector2Int.left,
  30. Vector2Int.down + Vector2Int.right
  31. };
  32. // helper function so we can add an entry without worrying
  33. public void Add(Vector2Int position, T value)
  34. {
  35. // initialize set in grid if it's not in there yet
  36. if (!grid.TryGetValue(position, out HashSet<T> hashSet))
  37. {
  38. hashSet = new HashSet<T>();
  39. grid[position] = hashSet;
  40. }
  41. // add to it
  42. hashSet.Add(value);
  43. }
  44. // helper function to get set at position without worrying
  45. // -> result is passed as parameter to avoid allocations
  46. // -> result is not cleared before. this allows us to pass the HashSet from
  47. // GetWithNeighbours and avoid .UnionWith which is very expensive.
  48. void GetAt(Vector2Int position, HashSet<T> result)
  49. {
  50. // return the set at position
  51. if (grid.TryGetValue(position, out HashSet<T> hashSet))
  52. {
  53. foreach (T entry in hashSet)
  54. result.Add(entry);
  55. }
  56. }
  57. // helper function to get at position and it's 8 neighbors without worrying
  58. // -> result is passed as parameter to avoid allocations
  59. public void GetWithNeighbours(Vector2Int position, HashSet<T> result)
  60. {
  61. // clear result first
  62. result.Clear();
  63. // add neighbours
  64. foreach (Vector2Int offset in neighbourOffsets)
  65. GetAt(position + offset, result);
  66. }
  67. // clear: clears the whole grid
  68. // IMPORTANT: we already allocated HashSet<T>s and don't want to do
  69. // reallocate every single update when we rebuild the grid.
  70. // => so simply remove each position's entries, but keep
  71. // every position in there
  72. // => see 'grid' comments above!
  73. // => named ClearNonAlloc to make it more obvious!
  74. public void ClearNonAlloc()
  75. {
  76. foreach (HashSet<T> hashSet in grid.Values)
  77. hashSet.Clear();
  78. }
  79. }
  80. }