Antkeeper  0.0.1
ant-swarm.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 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 
20 #include "game/ant/ant-swarm.hpp"
30 #include <engine/math/angles.hpp>
32 #include <engine/config.hpp>
33 #include <cmath>
34 #include <random>
35 
41 template <class T, class URBG>
42 static math::vec3<T> sphere_random(URBG& urbg)
43 {
44  std::uniform_real_distribution<T> distribution(T{-1}, T{1});
45 
47  for (std::size_t i = 0; i < 3; ++i)
48  position[i] = distribution(urbg);
49 
50  return math::normalize(position) * std::cbrt(distribution(urbg));
51 }
52 
54 {
55  // Determine swarm properties
56  const math::fvec3 swarm_center = {0, 100, 0};
57  const float swarm_radius = 25.0f;
58  const std::size_t male_count = 50;
59  const std::size_t queen_count = 50;
60  const std::size_t alate_count = male_count + queen_count;
61 
62  const math::fvec3 male_scale = {0.5, 0.5, 0.5};
63  const math::fvec3 queen_scale = {1, 1, 1};
64 
65  // Init transform component
66  ::transform_component transform;
68  transform.world = transform.local;
69 
70  // Init picking component
71  ::picking_component picking;
72  picking.sphere = {math::fvec3{0, 0, 0}, 0.5f * 2.0f};
73  std::uint32_t male_picking_flags = 0b01;
74  std::uint32_t queen_picking_flags = 0b10;
75 
76  // Create swarm entity
77  entity::id swarm_eid = ctx.entity_registry->create();
78  transform.local.translation = swarm_center;
79  transform.world = transform.local;
80  ctx.entity_registry->emplace<::transform_component>(swarm_eid, transform);
81 
82  // Load male model
83  std::shared_ptr<render::model> male_model = ctx.resource_manager->load<render::model>("male-boid.mdl");
84 
85  // Load queen model
86  std::shared_ptr<render::model> queen_model = ctx.resource_manager->load<render::model>("queen-boid.mdl");
87 
88  // Init steering component
89  ::steering_component steering;
90  steering.agent.mass = 1.0f;
91  steering.agent.velocity = {0, 0, 0};
92  steering.agent.acceleration = {0, 0, 0};
93  steering.agent.max_force = 4.0f;
94  steering.agent.max_speed = 5.0f;
95  steering.agent.max_speed_squared = steering.agent.max_speed * steering.agent.max_speed;
96  steering.agent.orientation = math::fquat::identity();
97  steering.agent.forward = steering.agent.orientation * config::global_forward;
98  steering.agent.up = steering.agent.orientation * config::global_up;
99  steering.wander_weight = 1.0f;
100  steering.wander_noise = math::radians(2000.0f);
101  steering.wander_distance = 10.0f;
102  steering.wander_radius = 8.0f;
103  steering.wander_angle = 0.0f;
104  steering.wander_angle2 = 0.0f;
105  steering.seek_weight = 0.2f;
106  steering.seek_target = swarm_center;
107  steering.flee_weight = 0.0f;
108  steering.sum_weights = steering.wander_weight + steering.seek_weight + steering.flee_weight;
109 
110  // Init rigid body
111  physics::rigid_body rigid_body;
112  rigid_body.set_mass(1.0f);
113 
114  // Init winged locomotion component
115  winged_locomotion_component winged_locomotion;
116 
117  // Init queen caste component
118  ant_caste_component queen_caste;
119  queen_caste.type = ant_caste_type::queen;
120 
121  // Init male caste component
122  ant_caste_component male_caste;
123  male_caste.type = ant_caste_type::male;
124 
125  // Create alates
126  for (std::size_t i = 0; i < alate_count; ++i)
127  {
128  // Generate random position in swarm sphere
129  steering.agent.position = swarm_center + sphere_random<float>(ctx.rng) * swarm_radius;
130  transform.local.translation = steering.agent.position;
131 
132  entity::id alate_eid = ctx.entity_registry->create();
133  ctx.entity_registry->emplace<::steering_component>(alate_eid, steering);
134  ctx.entity_registry->emplace<::rigid_body_component>(alate_eid, std::make_unique<physics::rigid_body>(rigid_body));
135  ctx.entity_registry->emplace<::winged_locomotion_component>(alate_eid, winged_locomotion);
136 
137  if (i < male_count)
138  {
139  // Create male
140  ctx.entity_registry->emplace<ant_caste_component>(alate_eid, male_caste);
141  ctx.entity_registry->emplace<::scene_component>(alate_eid, std::make_unique<scene::static_mesh>(male_model), std::uint8_t{1});
142 
143 
144  transform.local.scale = male_scale;
145  transform.world = transform.local;
146  ctx.entity_registry->emplace<::transform_component>(alate_eid, transform);
147 
148  picking.flags = male_picking_flags;
149  ctx.entity_registry->emplace<::picking_component>(alate_eid, picking);
150  }
151  else
152  {
153  // Create queen
154  ctx.entity_registry->emplace<ant_caste_component>(alate_eid, queen_caste);
155  ctx.entity_registry->emplace<::scene_component>(alate_eid, std::make_unique<scene::static_mesh>(queen_model), std::uint8_t{1});
156 
157  transform.local.scale = queen_scale;
158  transform.world = transform.local;
159  ctx.entity_registry->emplace<::transform_component>(alate_eid, transform);
160 
161  picking.flags = queen_picking_flags;
162  ctx.entity_registry->emplace<::picking_component>(alate_eid, picking);
163  }
164  }
165 
166  return swarm_eid;
167 }
168 
169 void destroy_ant_swarm(::game& ctx, entity::id swarm_eid)
170 {
171  // Destroy alates
172  auto view = ctx.entity_registry->view<::steering_component>();
173  ctx.entity_registry->destroy(view.begin(), view.end());
174 
175  // Destroy swarm
176  ctx.entity_registry->destroy(swarm_eid);
177 }
@ male
Male caste.
@ queen
Queen caste.
entity::id create_ant_swarm(::game &ctx)
Definition: ant-swarm.cpp:53
void destroy_ant_swarm(::game &ctx, entity::id swarm_eid)
Definition: ant-swarm.cpp:169
Definition: game.hpp:121
std::mt19937 rng
Definition: game.hpp:389
std::unique_ptr< resource_manager > resource_manager
Definition: game.hpp:152
std::unique_ptr< entity::registry > entity_registry
Definition: game.hpp:392
constexpr void set_mass(float mass) noexcept
Sets mass of the rigid body.
Definition: rigid-body.hpp:144
entt::entity id
Entity ID type.
Definition: id.hpp:28
quaternion< T > normalize(const quaternion< T > &q)
Normalizes a quaternion.
Definition: quaternion.hpp:679
constexpr T radians(T degrees) noexcept
Converts an angle given in degrees to radians.
Definition: angles.hpp:48
float mass
Mass of the agent.
Definition: agent.hpp:35
ant_caste_type type
Caste type.
static constexpr quaternion identity() noexcept
Returns a rotation identity quaternion.
Definition: quaternion.hpp:200
vector_type scale
Scale vector.
Definition: transform.hpp:56
static constexpr transform identity() noexcept
Returns an identity transform.
Definition: transform.hpp:107
vector_type translation
Translation vector.
Definition: transform.hpp:50
n-dimensional vector.
Definition: vector.hpp:44
std::uint32_t flags
Picking flags.
geom::sphere< float > sphere
Picking sphere.
ai::steering::agent agent
Steering agent.
math::transform< float > world
math::transform< float > local