guard_system_test.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #include "core/component.h"
  2. #include "core/entity.h"
  3. #include "core/world.h"
  4. #include "systems/guard_system.h"
  5. #include <gtest/gtest.h>
  6. using namespace Engine::Core;
  7. using namespace Game::Systems;
  8. class GuardSystemTest : public ::testing::Test {
  9. protected:
  10. void SetUp() override { world = std::make_unique<World>(); }
  11. void TearDown() override { world.reset(); }
  12. std::unique_ptr<World> world;
  13. GuardSystem guard_system;
  14. };
  15. TEST_F(GuardSystemTest, GuardFollowsMovingEntity) {
  16. // Create a unit that is guarding another unit
  17. auto *guard = world->create_entity();
  18. auto *guard_transform =
  19. guard->add_component<TransformComponent>(0.0F, 0.0F, 0.0F);
  20. auto *guard_unit = guard->add_component<UnitComponent>(100, 100, 1.0F, 12.0F);
  21. guard_unit->owner_id = 1;
  22. auto *guard_movement = guard->add_component<MovementComponent>();
  23. auto *guard_mode = guard->add_component<GuardModeComponent>();
  24. // Create the unit being guarded
  25. auto *guarded = world->create_entity();
  26. auto *guarded_transform =
  27. guarded->add_component<TransformComponent>(5.0F, 0.0F, 5.0F);
  28. auto *guarded_unit =
  29. guarded->add_component<UnitComponent>(100, 100, 1.0F, 12.0F);
  30. guarded_unit->owner_id = 1;
  31. // Setup guard mode to guard the entity
  32. guard_mode->active = true;
  33. guard_mode->guarded_entity_id = guarded->get_id();
  34. guard_mode->has_guard_target = true;
  35. guard_mode->guard_position_x = 5.0F;
  36. guard_mode->guard_position_z = 5.0F;
  37. // Run the guard system - distance is sqrt(50) ≈ 7.07, which exceeds
  38. // threshold of 2, so guard should move
  39. guard_system.update(world.get(), 0.1F);
  40. // Guard should have movement target set because the distance exceeds the
  41. // threshold
  42. EXPECT_TRUE(guard_movement->has_target);
  43. EXPECT_FLOAT_EQ(guard_movement->goal_x, 5.0F);
  44. EXPECT_FLOAT_EQ(guard_movement->goal_y,
  45. 5.0F); // goal_y represents Z coordinate
  46. // Move the guarded unit to a new position
  47. guarded_transform->position.x = 15.0F;
  48. guarded_transform->position.z = 15.0F;
  49. // Run the guard system again
  50. guard_system.update(world.get(), 0.1F);
  51. // Guard's stored position should be updated
  52. EXPECT_FLOAT_EQ(guard_mode->guard_position_x, 15.0F);
  53. EXPECT_FLOAT_EQ(guard_mode->guard_position_z, 15.0F);
  54. // Guard should have new movement target
  55. EXPECT_TRUE(guard_movement->has_target);
  56. EXPECT_FLOAT_EQ(guard_movement->goal_x, 15.0F);
  57. EXPECT_FLOAT_EQ(guard_movement->goal_y,
  58. 15.0F); // goal_y represents Z coordinate
  59. EXPECT_TRUE(guard_mode->returning_to_guard_position);
  60. }
  61. TEST_F(GuardSystemTest, GuardDoesNotFollowSmallMovements) {
  62. // Create a unit that is guarding another unit
  63. auto *guard = world->create_entity();
  64. auto *guard_transform =
  65. guard->add_component<TransformComponent>(5.0F, 0.0F, 5.0F);
  66. auto *guard_unit = guard->add_component<UnitComponent>(100, 100, 1.0F, 12.0F);
  67. guard_unit->owner_id = 1;
  68. auto *guard_movement = guard->add_component<MovementComponent>();
  69. auto *guard_mode = guard->add_component<GuardModeComponent>();
  70. // Create the unit being guarded (very close to guard)
  71. auto *guarded = world->create_entity();
  72. auto *guarded_transform =
  73. guarded->add_component<TransformComponent>(5.5F, 0.0F, 5.5F);
  74. auto *guarded_unit =
  75. guarded->add_component<UnitComponent>(100, 100, 1.0F, 12.0F);
  76. guarded_unit->owner_id = 1;
  77. // Setup guard mode to guard the entity
  78. guard_mode->active = true;
  79. guard_mode->guarded_entity_id = guarded->get_id();
  80. guard_mode->has_guard_target = true;
  81. guard_mode->guard_position_x = 5.5F;
  82. guard_mode->guard_position_z = 5.5F;
  83. // Run the guard system - guard should not move (distance is less than
  84. // threshold)
  85. guard_system.update(world.get(), 0.1F);
  86. // Guard should not have movement target set (distance too small)
  87. EXPECT_FALSE(guard_movement->has_target);
  88. }
  89. TEST_F(GuardSystemTest, GuardDoesNotFollowWhileAttacking) {
  90. // Create a unit that is guarding another unit
  91. auto *guard = world->create_entity();
  92. auto *guard_transform =
  93. guard->add_component<TransformComponent>(0.0F, 0.0F, 0.0F);
  94. auto *guard_unit = guard->add_component<UnitComponent>(100, 100, 1.0F, 12.0F);
  95. guard_unit->owner_id = 1;
  96. auto *guard_movement = guard->add_component<MovementComponent>();
  97. auto *guard_mode = guard->add_component<GuardModeComponent>();
  98. // Create the unit being guarded
  99. auto *guarded = world->create_entity();
  100. auto *guarded_transform =
  101. guarded->add_component<TransformComponent>(20.0F, 0.0F, 20.0F);
  102. auto *guarded_unit =
  103. guarded->add_component<UnitComponent>(100, 100, 1.0F, 12.0F);
  104. guarded_unit->owner_id = 1;
  105. // Setup guard mode to guard the entity
  106. guard_mode->active = true;
  107. guard_mode->guarded_entity_id = guarded->get_id();
  108. guard_mode->has_guard_target = true;
  109. guard_mode->guard_position_x = 5.0F;
  110. guard_mode->guard_position_z = 5.0F;
  111. // Create an enemy that the guard is attacking
  112. auto *enemy = world->create_entity();
  113. enemy->add_component<TransformComponent>(2.0F, 0.0F, 2.0F);
  114. auto *enemy_unit = enemy->add_component<UnitComponent>(100, 100, 1.0F, 10.0F);
  115. enemy_unit->owner_id = 2;
  116. // Guard is attacking the enemy
  117. auto *attack_target = guard->add_component<AttackTargetComponent>();
  118. attack_target->target_id = enemy->get_id();
  119. // Run the guard system
  120. guard_system.update(world.get(), 0.1F);
  121. // Guard should NOT follow the guarded unit while attacking
  122. EXPECT_FALSE(guard_movement->has_target);
  123. // Guard position should not have been updated
  124. EXPECT_FLOAT_EQ(guard_mode->guard_position_x, 5.0F);
  125. EXPECT_FLOAT_EQ(guard_mode->guard_position_z, 5.0F);
  126. }
  127. TEST_F(GuardSystemTest, GuardReturnsToPositionWhenGuardingLocation) {
  128. // Create a unit that is guarding a position (not an entity)
  129. auto *guard = world->create_entity();
  130. auto *guard_transform =
  131. guard->add_component<TransformComponent>(5.0F, 0.0F, 5.0F);
  132. auto *guard_unit = guard->add_component<UnitComponent>(100, 100, 1.0F, 12.0F);
  133. guard_unit->owner_id = 1;
  134. auto *guard_movement = guard->add_component<MovementComponent>();
  135. auto *guard_mode = guard->add_component<GuardModeComponent>();
  136. // Setup guard mode to guard a position (no entity)
  137. guard_mode->active = true;
  138. guard_mode->guarded_entity_id = 0; // No entity
  139. guard_mode->has_guard_target = true;
  140. guard_mode->guard_position_x = 10.0F;
  141. guard_mode->guard_position_z = 10.0F;
  142. guard_mode->returning_to_guard_position = false;
  143. // Run the guard system - guard should move back to guard position
  144. guard_system.update(world.get(), 0.1F);
  145. // Guard should have movement target set to return to guard position
  146. EXPECT_TRUE(guard_movement->has_target);
  147. EXPECT_FLOAT_EQ(guard_movement->goal_x, 10.0F);
  148. EXPECT_FLOAT_EQ(guard_movement->goal_y,
  149. 10.0F); // goal_y represents Z coordinate
  150. EXPECT_TRUE(guard_mode->returning_to_guard_position);
  151. }
  152. TEST_F(GuardSystemTest, GuardDoesNotMoveWhenAlreadyAtPosition) {
  153. // Create a unit that is guarding a position
  154. auto *guard = world->create_entity();
  155. auto *guard_transform =
  156. guard->add_component<TransformComponent>(10.0F, 0.0F, 10.0F);
  157. auto *guard_unit = guard->add_component<UnitComponent>(100, 100, 1.0F, 12.0F);
  158. guard_unit->owner_id = 1;
  159. auto *guard_movement = guard->add_component<MovementComponent>();
  160. auto *guard_mode = guard->add_component<GuardModeComponent>();
  161. // Setup guard mode to guard a position (already at position)
  162. guard_mode->active = true;
  163. guard_mode->guarded_entity_id = 0; // No entity
  164. guard_mode->has_guard_target = true;
  165. guard_mode->guard_position_x = 10.0F;
  166. guard_mode->guard_position_z = 10.0F;
  167. guard_mode->returning_to_guard_position = false;
  168. // Run the guard system
  169. guard_system.update(world.get(), 0.1F);
  170. // Guard should not move (already at position)
  171. EXPECT_FALSE(guard_movement->has_target);
  172. EXPECT_FALSE(guard_mode->returning_to_guard_position);
  173. }