spatial_grid.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #include "spatial_grid.h"
  2. #include <algorithm>
  3. #include <cmath>
  4. namespace Game::Systems {
  5. SpatialGrid::SpatialGrid(float cell_size)
  6. : m_cell_size(cell_size), m_inv_cell_size(1.0F / cell_size) {}
  7. void SpatialGrid::clear() {
  8. m_cells.clear();
  9. m_entity_cells.clear();
  10. }
  11. void SpatialGrid::insert(Engine::Core::EntityID entity_id, float x, float z) {
  12. CellKey const key = to_cell_key(x, z);
  13. m_cells[key].push_back(entity_id);
  14. m_entity_cells[entity_id] = key;
  15. }
  16. void SpatialGrid::remove(Engine::Core::EntityID entity_id) {
  17. auto it = m_entity_cells.find(entity_id);
  18. if (it == m_entity_cells.end()) {
  19. return;
  20. }
  21. CellKey const key = it->second;
  22. m_entity_cells.erase(it);
  23. auto cell_it = m_cells.find(key);
  24. if (cell_it != m_cells.end()) {
  25. auto &entities = cell_it->second;
  26. entities.erase(std::remove(entities.begin(), entities.end(), entity_id),
  27. entities.end());
  28. if (entities.empty()) {
  29. m_cells.erase(cell_it);
  30. }
  31. }
  32. }
  33. void SpatialGrid::update(Engine::Core::EntityID entity_id, float x, float z) {
  34. CellKey const new_key = to_cell_key(x, z);
  35. auto it = m_entity_cells.find(entity_id);
  36. if (it == m_entity_cells.end()) {
  37. insert(entity_id, x, z);
  38. return;
  39. }
  40. if (it->second == new_key) {
  41. return;
  42. }
  43. CellKey const old_key = it->second;
  44. auto cell_it = m_cells.find(old_key);
  45. if (cell_it != m_cells.end()) {
  46. auto &entities = cell_it->second;
  47. entities.erase(std::remove(entities.begin(), entities.end(), entity_id),
  48. entities.end());
  49. if (entities.empty()) {
  50. m_cells.erase(cell_it);
  51. }
  52. }
  53. m_cells[new_key].push_back(entity_id);
  54. it->second = new_key;
  55. }
  56. auto SpatialGrid::get_entities_in_range(float x, float z, float range) const
  57. -> std::vector<Engine::Core::EntityID> {
  58. std::vector<Engine::Core::EntityID> result;
  59. int const cells_to_check =
  60. static_cast<int>(std::ceil(range * m_inv_cell_size));
  61. CellKey const center = to_cell_key(x, z);
  62. float const range_sq = range * range;
  63. for (int dx = -cells_to_check; dx <= cells_to_check; ++dx) {
  64. for (int dz = -cells_to_check; dz <= cells_to_check; ++dz) {
  65. CellKey const key{center.x + dx, center.z + dz};
  66. auto it = m_cells.find(key);
  67. if (it == m_cells.end()) {
  68. continue;
  69. }
  70. if (std::abs(dx) <= 1 && std::abs(dz) <= 1) {
  71. result.insert(result.end(), it->second.begin(), it->second.end());
  72. } else {
  73. float const cell_center_x =
  74. (static_cast<float>(key.x) + 0.5F) * m_cell_size;
  75. float const cell_center_z =
  76. (static_cast<float>(key.z) + 0.5F) * m_cell_size;
  77. float const cell_dx = cell_center_x - x;
  78. float const cell_dz = cell_center_z - z;
  79. float const cell_dist_sq = cell_dx * cell_dx + cell_dz * cell_dz;
  80. float const cell_buffer = m_cell_size * 1.5F;
  81. if (cell_dist_sq <= (range + cell_buffer) * (range + cell_buffer)) {
  82. result.insert(result.end(), it->second.begin(), it->second.end());
  83. }
  84. }
  85. }
  86. }
  87. return result;
  88. }
  89. auto SpatialGrid::get_nearby_entities(float x, float z) const
  90. -> std::vector<Engine::Core::EntityID> {
  91. std::vector<Engine::Core::EntityID> result;
  92. CellKey const center = to_cell_key(x, z);
  93. for (int dx = -1; dx <= 1; ++dx) {
  94. for (int dz = -1; dz <= 1; ++dz) {
  95. CellKey const key{center.x + dx, center.z + dz};
  96. auto it = m_cells.find(key);
  97. if (it != m_cells.end()) {
  98. result.insert(result.end(), it->second.begin(), it->second.end());
  99. }
  100. }
  101. }
  102. return result;
  103. }
  104. auto SpatialGrid::to_cell_key(float x, float z) const -> CellKey {
  105. return CellKey{static_cast<int>(std::floor(x * m_inv_cell_size)),
  106. static_cast<int>(std::floor(z * m_inv_cell_size))};
  107. }
  108. } // namespace Game::Systems