catapult_attack_system.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. #include "catapult_attack_system.h"
  2. #include "../core/component.h"
  3. #include "../core/world.h"
  4. #include "../units/spawn_type.h"
  5. #include "../visuals/team_colors.h"
  6. #include "projectile_system.h"
  7. #include <cmath>
  8. #include <qvectornd.h>
  9. namespace Game::Systems {
  10. void CatapultAttackSystem::update(Engine::Core::World *world,
  11. float delta_time) {
  12. process_catapult_attacks(world, delta_time);
  13. }
  14. void CatapultAttackSystem::process_catapult_attacks(Engine::Core::World *world,
  15. float delta_time) {
  16. auto entities = world->get_entities_with<Engine::Core::UnitComponent>();
  17. for (auto *entity : entities) {
  18. auto *unit = entity->get_component<Engine::Core::UnitComponent>();
  19. if (unit == nullptr || unit->health <= 0) {
  20. continue;
  21. }
  22. if (unit->spawn_type != Game::Units::SpawnType::Catapult) {
  23. continue;
  24. }
  25. if (entity->has_component<Engine::Core::PendingRemovalComponent>()) {
  26. continue;
  27. }
  28. auto *loading =
  29. entity->get_component<Engine::Core::CatapultLoadingComponent>();
  30. if (loading == nullptr) {
  31. loading = entity->add_component<Engine::Core::CatapultLoadingComponent>();
  32. }
  33. auto *movement = entity->get_component<Engine::Core::MovementComponent>();
  34. if (movement != nullptr) {
  35. constexpr float k_movement_threshold = 0.01F;
  36. bool is_moving = (std::abs(movement->vx) > k_movement_threshold ||
  37. std::abs(movement->vz) > k_movement_threshold);
  38. if (is_moving &&
  39. loading->state !=
  40. Engine::Core::CatapultLoadingComponent::LoadingState::Idle) {
  41. loading->state =
  42. Engine::Core::CatapultLoadingComponent::LoadingState::Idle;
  43. loading->loading_time = 0.0F;
  44. loading->firing_time = 0.0F;
  45. loading->target_position_locked = false;
  46. loading->target_id = 0;
  47. }
  48. }
  49. switch (loading->state) {
  50. case Engine::Core::CatapultLoadingComponent::LoadingState::Idle: {
  51. auto *attack_target =
  52. entity->get_component<Engine::Core::AttackTargetComponent>();
  53. if (attack_target != nullptr && attack_target->target_id != 0) {
  54. auto *target = world->get_entity(attack_target->target_id);
  55. if (target != nullptr &&
  56. !target->has_component<Engine::Core::PendingRemovalComponent>()) {
  57. auto *target_unit =
  58. target->get_component<Engine::Core::UnitComponent>();
  59. if (target_unit != nullptr && target_unit->health > 0) {
  60. auto *transform =
  61. entity->get_component<Engine::Core::TransformComponent>();
  62. auto *target_transform =
  63. target->get_component<Engine::Core::TransformComponent>();
  64. auto *attack =
  65. entity->get_component<Engine::Core::AttackComponent>();
  66. if (transform != nullptr && target_transform != nullptr &&
  67. attack != nullptr) {
  68. float const dx =
  69. target_transform->position.x - transform->position.x;
  70. float const dz =
  71. target_transform->position.z - transform->position.z;
  72. float const dist = std::sqrt(dx * dx + dz * dz);
  73. if (dist <= attack->range) {
  74. start_loading(entity, target);
  75. }
  76. }
  77. }
  78. }
  79. }
  80. break;
  81. }
  82. case Engine::Core::CatapultLoadingComponent::LoadingState::Loading: {
  83. update_loading(entity, delta_time);
  84. break;
  85. }
  86. case Engine::Core::CatapultLoadingComponent::LoadingState::ReadyToFire: {
  87. fire_projectile(world, entity);
  88. break;
  89. }
  90. case Engine::Core::CatapultLoadingComponent::LoadingState::Firing: {
  91. update_firing(entity, delta_time);
  92. break;
  93. }
  94. }
  95. }
  96. }
  97. void CatapultAttackSystem::start_loading(Engine::Core::Entity *catapult,
  98. Engine::Core::Entity *target) {
  99. auto *loading =
  100. catapult->get_component<Engine::Core::CatapultLoadingComponent>();
  101. if (loading == nullptr) {
  102. return;
  103. }
  104. auto *target_transform =
  105. target->get_component<Engine::Core::TransformComponent>();
  106. if (target_transform == nullptr) {
  107. return;
  108. }
  109. loading->state =
  110. Engine::Core::CatapultLoadingComponent::LoadingState::Loading;
  111. loading->loading_time = 0.0F;
  112. loading->target_id = target->get_id();
  113. loading->target_locked_x = target_transform->position.x;
  114. loading->target_locked_y = target_transform->position.y;
  115. loading->target_locked_z = target_transform->position.z;
  116. loading->target_position_locked = true;
  117. auto *catapult_transform =
  118. catapult->get_component<Engine::Core::TransformComponent>();
  119. if (catapult_transform != nullptr) {
  120. float const dx =
  121. target_transform->position.x - catapult_transform->position.x;
  122. float const dz =
  123. target_transform->position.z - catapult_transform->position.z;
  124. float const yaw = std::atan2(dx, dz) * 180.0F / 3.14159265F;
  125. catapult_transform->desired_yaw = yaw;
  126. catapult_transform->has_desired_yaw = true;
  127. }
  128. }
  129. void CatapultAttackSystem::update_loading(Engine::Core::Entity *catapult,
  130. float delta_time) {
  131. auto *loading =
  132. catapult->get_component<Engine::Core::CatapultLoadingComponent>();
  133. if (loading == nullptr) {
  134. return;
  135. }
  136. loading->loading_time += delta_time;
  137. if (loading->loading_time >= loading->loading_duration) {
  138. loading->state =
  139. Engine::Core::CatapultLoadingComponent::LoadingState::ReadyToFire;
  140. }
  141. }
  142. void CatapultAttackSystem::fire_projectile(Engine::Core::World *world,
  143. Engine::Core::Entity *catapult) {
  144. auto *loading =
  145. catapult->get_component<Engine::Core::CatapultLoadingComponent>();
  146. if (loading == nullptr) {
  147. return;
  148. }
  149. auto *projectile_sys = world->get_system<ProjectileSystem>();
  150. if (projectile_sys == nullptr) {
  151. loading->state = Engine::Core::CatapultLoadingComponent::LoadingState::Idle;
  152. loading->loading_time = 0.0F;
  153. loading->target_position_locked = false;
  154. return;
  155. }
  156. auto *transform = catapult->get_component<Engine::Core::TransformComponent>();
  157. auto *attack = catapult->get_component<Engine::Core::AttackComponent>();
  158. auto *unit = catapult->get_component<Engine::Core::UnitComponent>();
  159. if (transform == nullptr || attack == nullptr) {
  160. loading->state = Engine::Core::CatapultLoadingComponent::LoadingState::Idle;
  161. loading->loading_time = 0.0F;
  162. loading->target_position_locked = false;
  163. return;
  164. }
  165. QVector3D const start(transform->position.x, transform->position.y + 1.5F,
  166. transform->position.z);
  167. QVector3D const end(loading->target_locked_x, loading->target_locked_y,
  168. loading->target_locked_z);
  169. QVector3D color(0.45F, 0.42F, 0.38F);
  170. if (unit != nullptr) {
  171. color = Game::Visuals::team_colorForOwner(unit->owner_id);
  172. }
  173. constexpr float k_stone_speed = 8.0F;
  174. constexpr float k_stone_scale = 1.5F;
  175. projectile_sys->spawn_stone(start, end, color, k_stone_speed, k_stone_scale,
  176. true, attack->damage, catapult->get_id(),
  177. loading->target_id);
  178. loading->state = Engine::Core::CatapultLoadingComponent::LoadingState::Firing;
  179. loading->firing_time = 0.0F;
  180. }
  181. void CatapultAttackSystem::update_firing(Engine::Core::Entity *catapult,
  182. float delta_time) {
  183. auto *loading =
  184. catapult->get_component<Engine::Core::CatapultLoadingComponent>();
  185. if (loading == nullptr) {
  186. return;
  187. }
  188. loading->firing_time += delta_time;
  189. if (loading->firing_time >= loading->firing_duration) {
  190. loading->state = Engine::Core::CatapultLoadingComponent::LoadingState::Idle;
  191. loading->loading_time = 0.0F;
  192. loading->firing_time = 0.0F;
  193. loading->target_position_locked = false;
  194. auto *attack = catapult->get_component<Engine::Core::AttackComponent>();
  195. if (attack != nullptr) {
  196. attack->time_since_last = 0.0F;
  197. }
  198. }
  199. }
  200. } // namespace Game::Systems