💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
5.6 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "game/ant/swarm.hpp"
  20. #include "game/component/transform.hpp"
  21. #include "game/component/steering.hpp"
  22. #include "game/component/model.hpp"
  23. #include "game/component/picking.hpp"
  24. #include "resources/resource-manager.hpp"
  25. #include "math/quaternion.hpp"
  26. #include "config.hpp"
  27. #include <cmath>
  28. #include <random>
  29. namespace game {
  30. namespace ant {
  31. /**
  32. * Generates a random point in a unit sphere.
  33. *
  34. * @see https://math.stackexchange.com/questions/87230/picking-random-points-in-the-volume-of-sphere-with-uniform-probability/87238#87238
  35. */
  36. template <class T, class Generator>
  37. static math::vector3<T> sphere_random(Generator& rng)
  38. {
  39. const std::uniform_real_distribution<T> distribution(T{-1}, T{1});
  40. math::vector3<T> position;
  41. for (std::size_t i = 0; i < 3; ++i)
  42. position[i] = distribution(rng);
  43. return math::normalize(position) * std::cbrt(distribution(rng));
  44. }
  45. entity::id create_swarm(game::context& ctx)
  46. {
  47. // Determine swarm properties
  48. const float3 swarm_center = {0, 100, 0};
  49. const float swarm_radius = 25.0f;
  50. const std::size_t male_count = 50;
  51. const std::size_t queen_count = 50;
  52. const std::size_t alate_count = male_count + queen_count;
  53. const float3 male_scale = {0.5, 0.5, 0.5};
  54. const float3 queen_scale = {1, 1, 1};
  55. // Init transform component
  56. game::component::transform transform;
  57. transform.local = math::transform<float>::identity;
  58. transform.world = transform.local;
  59. transform.warp = true;
  60. // Init picking component
  61. game::component::picking picking;
  62. picking.sphere = {float3{0, 0, 0}, 0.5f * 2.0f};
  63. std::uint32_t male_picking_flags = 0b01;
  64. std::uint32_t queen_picking_flags = 0b10;
  65. // Create swarm entity
  66. entity::id swarm_eid = ctx.entity_registry->create();
  67. transform.local.translation = swarm_center;
  68. transform.world = transform.local;
  69. transform.warp = true;
  70. ctx.entity_registry->emplace<game::component::transform>(swarm_eid, transform);
  71. // Init male model component
  72. game::component::model male_model;
  73. male_model.render_model = ctx.resource_manager->load<render::model>("male-boid.mdl");
  74. male_model.instance_count = 0;
  75. male_model.layers = 1;
  76. // Init queen model component
  77. game::component::model queen_model;
  78. queen_model.render_model = ctx.resource_manager->load<render::model>("queen-boid.mdl");
  79. queen_model.instance_count = 0;
  80. queen_model.layers = 1;
  81. // Init steering component
  82. game::component::steering steering;
  83. steering.agent.mass = 1.0f;
  84. steering.agent.velocity = {0, 0, 0};
  85. steering.agent.acceleration = {0, 0, 0};
  86. steering.agent.max_force = 4.0f;
  87. steering.agent.max_speed = 5.0f;
  88. steering.agent.max_speed_squared = steering.agent.max_speed * steering.agent.max_speed;
  89. steering.agent.orientation = math::quaternion<float>::identity();
  90. steering.agent.forward = steering.agent.orientation * config::global_forward;
  91. steering.agent.up = steering.agent.orientation * config::global_up;
  92. steering.wander_weight = 1.0f;
  93. steering.wander_noise = math::radians(2000.0f);
  94. steering.wander_distance = 10.0f;
  95. steering.wander_radius = 8.0f;
  96. steering.wander_angle = 0.0f;
  97. steering.wander_angle2 = 0.0f;
  98. steering.seek_weight = 0.2f;
  99. steering.seek_target = swarm_center;
  100. steering.flee_weight = 0.0f;
  101. steering.sum_weights = steering.wander_weight + steering.seek_weight + steering.flee_weight;
  102. // Construct and seed random number generator
  103. std::random_device seed;
  104. std::mt19937 rng(seed());
  105. // Create alates
  106. for (std::size_t i = 0; i < alate_count; ++i)
  107. {
  108. // Generate random position in swarm sphere
  109. steering.agent.position = swarm_center + sphere_random<float>(rng) * swarm_radius;
  110. transform.local.translation = steering.agent.position;
  111. entity::id alate_eid = ctx.entity_registry->create();
  112. ctx.entity_registry->emplace<game::component::steering>(alate_eid, steering);
  113. if (i < male_count)
  114. {
  115. // Create male
  116. ctx.entity_registry->emplace<game::component::model>(alate_eid, male_model);
  117. transform.local.scale = male_scale;
  118. transform.world = transform.local;
  119. ctx.entity_registry->emplace<game::component::transform>(alate_eid, transform);
  120. picking.flags = male_picking_flags;
  121. ctx.entity_registry->emplace<game::component::picking>(alate_eid, picking);
  122. }
  123. else
  124. {
  125. // Create queen
  126. ctx.entity_registry->emplace<game::component::model>(alate_eid, queen_model);
  127. transform.local.scale = queen_scale;
  128. transform.world = transform.local;
  129. ctx.entity_registry->emplace<game::component::transform>(alate_eid, transform);
  130. picking.flags = queen_picking_flags;
  131. ctx.entity_registry->emplace<game::component::picking>(alate_eid, picking);
  132. }
  133. }
  134. return swarm_eid;
  135. }
  136. void destroy_swarm(game::context& ctx, entity::id swarm_eid)
  137. {
  138. // Destroy alates
  139. auto view = ctx.entity_registry->view<game::component::steering>();
  140. ctx.entity_registry->destroy(view.begin(), view.end());
  141. // Destroy swarm
  142. ctx.entity_registry->destroy(swarm_eid);
  143. }
  144. } // namespace ant
  145. } // namespace game