building_collision_test.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #include "systems/building_collision_registry.h"
  2. #include <gtest/gtest.h>
  3. using namespace Game::Systems;
  4. namespace {
  5. constexpr float kDefaultGridCellSize = 1.0F;
  6. } // namespace
  7. class BuildingCollisionRegistryTest : public ::testing::Test {
  8. protected:
  9. void SetUp() override { BuildingCollisionRegistry::instance().clear(); }
  10. void TearDown() override { BuildingCollisionRegistry::instance().clear(); }
  11. };
  12. TEST_F(BuildingCollisionRegistryTest, PointInsideBuilding) {
  13. auto &registry = BuildingCollisionRegistry::instance();
  14. registry.register_building(1, "barracks", 0.0F, 0.0F, 0);
  15. EXPECT_TRUE(registry.is_point_in_building(0.0F, 0.0F));
  16. EXPECT_TRUE(registry.is_point_in_building(1.0F, 1.0F));
  17. EXPECT_FALSE(registry.is_point_in_building(10.0F, 10.0F));
  18. }
  19. TEST_F(BuildingCollisionRegistryTest, PointOutsideBuilding) {
  20. auto &registry = BuildingCollisionRegistry::instance();
  21. registry.register_building(1, "barracks", 0.0F, 0.0F, 0);
  22. EXPECT_FALSE(registry.is_point_in_building(5.0F, 0.0F));
  23. EXPECT_FALSE(registry.is_point_in_building(0.0F, 5.0F));
  24. EXPECT_FALSE(registry.is_point_in_building(-5.0F, 0.0F));
  25. EXPECT_FALSE(registry.is_point_in_building(0.0F, -5.0F));
  26. }
  27. TEST_F(BuildingCollisionRegistryTest, CircleOverlappingBuilding) {
  28. auto &registry = BuildingCollisionRegistry::instance();
  29. registry.register_building(1, "barracks", 0.0F, 0.0F, 0);
  30. EXPECT_TRUE(registry.is_circle_overlapping_building(0.0F, 0.0F, 0.5F));
  31. EXPECT_TRUE(registry.is_circle_overlapping_building(1.0F, 1.0F, 0.5F));
  32. EXPECT_TRUE(registry.is_circle_overlapping_building(2.5F, 0.0F, 1.0F));
  33. }
  34. TEST_F(BuildingCollisionRegistryTest, CircleNotOverlappingBuilding) {
  35. auto &registry = BuildingCollisionRegistry::instance();
  36. registry.register_building(1, "barracks", 0.0F, 0.0F, 0);
  37. EXPECT_FALSE(registry.is_circle_overlapping_building(10.0F, 0.0F, 0.5F));
  38. EXPECT_FALSE(registry.is_circle_overlapping_building(0.0F, 10.0F, 0.5F));
  39. EXPECT_FALSE(registry.is_circle_overlapping_building(5.0F, 0.0F, 0.5F));
  40. }
  41. TEST_F(BuildingCollisionRegistryTest, CircleTouchingBuildingEdge) {
  42. auto &registry = BuildingCollisionRegistry::instance();
  43. registry.register_building(1, "barracks", 0.0F, 0.0F, 0);
  44. EXPECT_TRUE(registry.is_circle_overlapping_building(2.0F, 0.0F, 0.5F));
  45. EXPECT_TRUE(registry.is_circle_overlapping_building(3.0F, 0.0F, 1.0F));
  46. }
  47. TEST_F(BuildingCollisionRegistryTest, LargeUnitRadiusPreventedFromClipping) {
  48. auto &registry = BuildingCollisionRegistry::instance();
  49. registry.register_building(1, "barracks", 0.0F, 0.0F, 0);
  50. float const large_radius = 2.0F;
  51. EXPECT_TRUE(
  52. registry.is_circle_overlapping_building(3.5F, 0.0F, large_radius));
  53. EXPECT_TRUE(
  54. registry.is_circle_overlapping_building(0.0F, 3.5F, large_radius));
  55. EXPECT_FALSE(
  56. registry.is_circle_overlapping_building(5.0F, 0.0F, large_radius));
  57. }
  58. TEST_F(BuildingCollisionRegistryTest, IgnoreEntityId) {
  59. auto &registry = BuildingCollisionRegistry::instance();
  60. registry.register_building(1, "barracks", 0.0F, 0.0F, 0);
  61. registry.register_building(2, "barracks", 10.0F, 10.0F, 0);
  62. EXPECT_TRUE(registry.is_circle_overlapping_building(0.0F, 0.0F, 0.5F, 0));
  63. EXPECT_FALSE(registry.is_circle_overlapping_building(0.0F, 0.0F, 0.5F, 1));
  64. EXPECT_TRUE(registry.is_circle_overlapping_building(10.0F, 10.0F, 0.5F, 1));
  65. }
  66. TEST_F(BuildingCollisionRegistryTest, MultipleBuildings) {
  67. auto &registry = BuildingCollisionRegistry::instance();
  68. registry.register_building(1, "barracks", 0.0F, 0.0F, 0);
  69. registry.register_building(2, "barracks", 10.0F, 0.0F, 0);
  70. EXPECT_TRUE(registry.is_circle_overlapping_building(0.0F, 0.0F, 0.5F));
  71. EXPECT_TRUE(registry.is_circle_overlapping_building(10.0F, 0.0F, 0.5F));
  72. EXPECT_FALSE(registry.is_circle_overlapping_building(5.0F, 0.0F, 0.5F));
  73. }
  74. TEST_F(BuildingCollisionRegistryTest, GridPaddingAccountsForUnitRadius) {
  75. auto &registry = BuildingCollisionRegistry::instance();
  76. // Barracks is 4x4, centered at (0,0), so bounds are [-2, 2] x [-2, 2]
  77. registry.register_building(1, "barracks", 0.0F, 0.0F, 0);
  78. // Default grid padding should be at least 1.0 to account for largest unit
  79. // sizes
  80. EXPECT_GE(BuildingCollisionRegistry::get_grid_padding(), 1.0F);
  81. // Get occupied grid cells and verify they include padding
  82. const auto &buildings = registry.get_all_buildings();
  83. ASSERT_EQ(buildings.size(), 1);
  84. auto cells = BuildingCollisionRegistry::get_occupied_grid_cells(
  85. buildings[0], kDefaultGridCellSize);
  86. // With padding of 1.0 and building bounds [-2, 2]:
  87. // min_grid should be floor(-2 - 1.0) = -3
  88. // max_grid should be ceil(2 + 1.0) = 3
  89. // So cells should span from -3 to 2 (since loop uses < max_grid)
  90. bool has_min_x = false;
  91. bool has_max_x = false;
  92. for (const auto &cell : cells) {
  93. if (cell.first <= -2)
  94. has_min_x = true;
  95. if (cell.first >= 2)
  96. has_max_x = true;
  97. }
  98. EXPECT_TRUE(has_min_x);
  99. EXPECT_TRUE(has_max_x);
  100. }
  101. TEST_F(BuildingCollisionRegistryTest, UnitWithLargeRadiusCloseToBuilding) {
  102. auto &registry = BuildingCollisionRegistry::instance();
  103. // Barracks is 4x4, centered at (0,0), so bounds are [-2, 2] x [-2, 2]
  104. registry.register_building(1, "barracks", 0.0F, 0.0F, 0);
  105. // Unit with radius 1.0 (mounted knight-sized)
  106. float const unit_radius = 1.0F;
  107. // Building edge is at x=2. Unit center at x=2.5 with radius 1.0
  108. // would extend from x=1.5 to x=3.5, overlapping the building
  109. EXPECT_TRUE(registry.is_circle_overlapping_building(2.5F, 0.0F, unit_radius));
  110. // Unit center at x=3.0 with radius 1.0 would extend from x=2.0 to x=4.0
  111. // x=2.0 is exactly at the building edge, so should still overlap
  112. EXPECT_TRUE(registry.is_circle_overlapping_building(3.0F, 0.0F, unit_radius));
  113. // Unit center at x=3.1 with radius 1.0 would extend from x=2.1 to x=4.1
  114. // This should not overlap since building ends at x=2.0
  115. EXPECT_FALSE(
  116. registry.is_circle_overlapping_building(3.1F, 0.0F, unit_radius));
  117. }