Antkeeper  0.0.1
ant-controls.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/controls.hpp"
21 #include "game/world.hpp"
30 #include <engine/debug/log.hpp>
31 
32 namespace {
33 
39  void steer_controlled_ant(::game& ctx)
40  {
41  if (ctx.controlled_ant_eid == entt::null)
42  {
43  return;
44  }
45 
46  // Build control vector
47  math::fvec2 control_vector = {};
48  control_vector.x() -= ctx.ant_move_left_action.get_input_value();
49  control_vector.x() += ctx.ant_move_right_action.get_input_value();
50  control_vector.y() -= ctx.ant_move_forward_action.get_input_value();
51  control_vector.y() += ctx.ant_move_back_action.get_input_value();
52 
53  // Get locomotion component of controlled ant
54  auto& locomotion = ctx.entity_registry->get<legged_locomotion_component>(ctx.controlled_ant_eid);
55 
56  // Get phenome of controlled ant caste
57  const auto& caste_phenome = *ctx.entity_registry->get<::ant_caste_component>(ctx.controlled_ant_eid).phenome;
58 
59  // Determine control direction and magnitude
60  math::fvec2 control_direction{};
61  float control_magnitude = 0.0f;
62  if (auto sqr_length = math::sqr_length(control_vector))
63  {
64  control_magnitude = std::sqrt(sqr_length);
65  control_direction = control_vector / control_magnitude;
66  }
67 
68  // Clamp control magnitude
69  const auto clamped_control_magnitude = std::min(1.0f, control_magnitude);
70 
71  // Determine locomotive speed
72  float locomotive_speed;
74  {
75  // Interpolate locomotive speed between walking and creeping
76  locomotive_speed = math::lerp(caste_phenome.legs->walking_speed, caste_phenome.legs->creeping_speed, ctx.ant_move_slow_action.get_input_value());
77  }
78  else if (ctx.ant_move_fast_action.is_active())
79  {
80  // Interpolate locomotive speed between walking and running
81  locomotive_speed = math::lerp(caste_phenome.legs->walking_speed, caste_phenome.legs->running_speed, ctx.ant_move_fast_action.get_input_value());
82  }
83  else
84  {
85  // Set locomotive speed to walking speed
86  locomotive_speed = caste_phenome.legs->walking_speed;
87  }
88 
89  // Scale locomotive speed by clamped control magnitude
90  locomotive_speed *= clamped_control_magnitude;
91 
92  // Scale locomotive speed by scale of controlled ant
93  auto& rigid_body = *ctx.entity_registry->get<rigid_body_component>(ctx.controlled_ant_eid).body;
94  locomotive_speed *= rigid_body.get_scale().x();
95 
96  locomotion.speed = locomotive_speed;
97  locomotion.angular_velocity = 0.0f;
98 
99  if (!locomotive_speed || ctx.active_camera_eid == entt::null)
100  {
101  return;
102  }
103 
104  const auto& spring_arm = ctx.entity_registry->get<spring_arm_component>(ctx.active_camera_eid);
105 
106  // Calculate steering direction
107  const auto spring_arm_yaw_rotation = math::angle_axis(spring_arm.angles_spring.get_value().y(), {0.0, 1.0, 0.0});
108  locomotion.target_direction = math::fquat(math::normalize(spring_arm.up_rotation * spring_arm_yaw_rotation)) * math::fvec3{control_direction.x(), 0.0f, (spring_arm.angles_spring.get_value().x() > 0.0) ? -control_direction.y() : control_direction.y()};
109  }
110 
117  void turn_controlled_ant(::game& ctx, float scale)
118  {
119  if (ctx.controlled_ant_eid == entt::null)
120  {
121  return;
122  }
123 
125  (
126  ctx.controlled_ant_eid,
127  [&](auto& component)
128  {
129  component.angular_velocity = math::radians(120.0f) * scale;
130  }
131  );
132  }
133 }
134 
136 {
137  // Ant move forward
138  ctx.event_subscriptions.emplace_back
139  (
141  (
142  [&](const auto& event)
143  {
144  steer_controlled_ant(ctx);
145  }
146  )
147  );
148  ctx.event_subscriptions.emplace_back
149  (
151  (
152  [&](const auto& event)
153  {
154  steer_controlled_ant(ctx);
155  }
156  )
157  );
158 
159  // Ant move back
160  ctx.event_subscriptions.emplace_back
161  (
163  (
164  [&](const auto& event)
165  {
166  steer_controlled_ant(ctx);
167  }
168  )
169  );
170  ctx.event_subscriptions.emplace_back
171  (
173  (
174  [&](const auto& event)
175  {
176  steer_controlled_ant(ctx);
177  }
178  )
179  );
180 
181  // Ant move left
182  ctx.event_subscriptions.emplace_back
183  (
185  (
186  [&](const auto& event)
187  {
188  steer_controlled_ant(ctx);
189  }
190  )
191  );
192  ctx.event_subscriptions.emplace_back
193  (
195  (
196  [&](const auto& event)
197  {
198  steer_controlled_ant(ctx);
199  }
200  )
201  );
202 
203  // Ant move right
204  ctx.event_subscriptions.emplace_back
205  (
207  (
208  [&](const auto& event)
209  {
210  steer_controlled_ant(ctx);
211  }
212  )
213  );
214  ctx.event_subscriptions.emplace_back
215  (
217  (
218  [&](const auto& event)
219  {
220  steer_controlled_ant(ctx);
221  }
222  )
223  );
224 
225  // Ant interact
226  ctx.event_subscriptions.emplace_back
227  (
229  (
230  [&](const auto& event)
231  {
232  if (ctx.active_camera_eid == entt::null)
233  {
234  return;
235  }
236 
237  auto& camera_object = *ctx.entity_registry->get<scene_component>(ctx.active_camera_eid).object;
238 
239  camera_object.set_layer_mask(camera_object.get_layer_mask() == 1 ? 2 : 1);
240  }
241  )
242  );
243 
244  // Ant oviposit
245  ctx.event_subscriptions.emplace_back
246  (
248  (
249  [&](const auto& event)
250  {
251  if (ctx.controlled_ant_eid == entt::null)
252  {
253  return;
254  }
255 
257  {
258  ovary_component->ovipositing = true;
259  }
260  }
261  )
262  );
263  ctx.event_subscriptions.emplace_back
264  (
266  (
267  [&](const auto& event)
268  {
269  if (ctx.controlled_ant_eid == entt::null)
270  {
271  return;
272  }
273 
275  {
276  ovary_component->ovipositing = false;
277  }
278  }
279  )
280  );
281 }
282 
284 {
285  ctx.ant_action_map.enable();
286 }
287 
289 {
290  ctx.ant_action_map.disable();
291  ctx.ant_action_map.reset();
292 }
void disable_ant_controls(::game &ctx)
void enable_ant_controls(::game &ctx)
void setup_ant_controls(::game &ctx)
Definition: game.hpp:121
input::action ant_move_fast_action
Definition: game.hpp:255
input::action ant_move_back_action
Definition: game.hpp:252
input::action ant_oviposit_action
Definition: game.hpp:258
entity::id active_camera_eid
Definition: game.hpp:395
input::action ant_interact_action
Definition: game.hpp:257
input::action_map ant_action_map
Definition: game.hpp:250
input::action ant_move_slow_action
Definition: game.hpp:256
std::vector< std::shared_ptr<::event::subscription > > event_subscriptions
Definition: game.hpp:265
input::action ant_move_right_action
Definition: game.hpp:254
input::action ant_move_forward_action
Definition: game.hpp:251
entity::id controlled_ant_eid
Definition: game.hpp:394
std::unique_ptr< entity::registry > entity_registry
Definition: game.hpp:392
input::action ant_move_left_action
Definition: game.hpp:253
void disable()
Disables the mapping of input events to actions.
Definition: action-map.cpp:41
void reset()
Resets the activation states of each action in the action map.
Definition: action-map.cpp:54
void enable()
Enables the mapping of input events to actions.
Definition: action-map.cpp:28
::event::channel< action_active_event > & get_active_channel() noexcept
Returns the channel through which action active events are published.
Definition: action.hpp:97
bool is_active() const noexcept
Returns true if the action is active, false otherwise.
Definition: action.hpp:79
float get_input_value() const noexcept
Returns the most recently evaluated input value.
Definition: action.hpp:85
::event::channel< action_deactivated_event > & get_deactivated_channel() noexcept
Returns the channel through which action deactivated events are published.
Definition: action.hpp:103
::event::channel< action_activated_event > & get_activated_channel() noexcept
Returns the channel through which action activated events are published.
Definition: action.hpp:91
Publish-subscribe messaging.
Definition: channel.hpp:32
quat< float > fquat
Quaternion with single-precision floating-point scalars.
Definition: quaternion.hpp:218
quaternion< T > normalize(const quaternion< T > &q)
Normalizes a quaternion.
Definition: quaternion.hpp:679
quaternion< T > angle_axis(T angle, const vec3< T > &axis)
Creates a rotation from an angle and axis.
Definition: quaternion.hpp:685
constexpr T radians(T degrees) noexcept
Converts an angle given in degrees to radians.
Definition: angles.hpp:48
constexpr T sqr_length(const quaternion< T > &q) noexcept
Calculates the square length of a quaternion.
Definition: quaternion.hpp:744
constexpr mat4< T > scale(const vec3< T > &v)
Constructs a scale matrix.
vector< T, N > sqrt(const vector< T, N > &x)
Takes the square root of each element.
constexpr T lerp(const T &x, const T &y, S a) noexcept
Linearly interpolates between x and y.
constexpr vector< T, N > min(const vector< T, N > &x, const vector< T, N > &y)
Returns a vector containing the minimum elements of two vectors.
Definition: vector.hpp:1347
Legged terrestrial locomotion.
n-dimensional vector.
Definition: vector.hpp:44
constexpr element_type & x() noexcept
Returns a reference to the first element.
Definition: vector.hpp:164
constexpr element_type & y() noexcept
Returns a reference to the second element.
Definition: vector.hpp:180
std::shared_ptr< scene::object_base > object
Attaches a camera to an entity using springs.