@ -1,90 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_GEOM_CLOSEST_FEATURE_HPP | |||
#define ANTKEEPER_GEOM_CLOSEST_FEATURE_HPP | |||
#include <engine/geom/primitives/point.hpp> | |||
#include <engine/geom/primitives/triangle.hpp> | |||
#include <algorithm> | |||
#include <tuple> | |||
namespace geom { | |||
/** | |||
* Calculates the closest features on a triangle to a point. | |||
* | |||
* @tparam T Real type. | |||
* | |||
* @param tri Triangle. | |||
* @param a First point of triangle. | |||
* @param b Second point of triangle. | |||
* @param c Third point of triangle. | |||
* @param p Point. | |||
* | |||
* @return Tuple containing the Barycentric coordinates of the closest point on the triangle to point @p p, followed by the index of the edge on which the point lies (`-1` if not on an edge). | |||
*/ | |||
/// @{ | |||
template <class T> | |||
[[nodiscard]] constexpr std::tuple<point<T, 3>, int> closest_feature(const point<T, 3>& a, const point<T, 3>& b, const point<T, 3>& c, const point<T, 3>& p) noexcept | |||
{ | |||
const auto ab = b - a; | |||
const auto ca = a - c; | |||
const auto ap = p - a; | |||
const auto n = math::cross(ab, ca); | |||
const auto d = math::sqr_length(n); | |||
const auto q = math::cross(n, ap); | |||
point<T, 3> uvw; | |||
if ((uvw.z() = math::dot(q, ab) / d) < T{0}) | |||
{ | |||
uvw.z() = T{0}; | |||
uvw.y() = std::min<T>(std::max<T>(math::dot(ab, ap) / math::sqr_length(ab), T{0}), T{1}); | |||
uvw.x() = T{1} - uvw.y(); | |||
return {uvw, 0}; | |||
} | |||
else if ((uvw.y() = math::dot(q, ca) / d) < T{0}) | |||
{ | |||
uvw.y() = T{0}; | |||
uvw.x() = std::min<T>(std::max<T>(math::dot(ca, p - c) / math::sqr_length(ca), T{0}), T{1}); | |||
uvw.z() = T{1} - uvw.x(); | |||
return {uvw, 2}; | |||
} | |||
else if ((uvw.x() = T{1} - uvw.y() - uvw.z()) < T{0}) | |||
{ | |||
uvw.x() = T{0}; | |||
const auto bc = c - b; | |||
uvw.z() = std::min<T>(std::max<T>(math::dot(bc, p - b) / math::sqr_length(bc), T{0}), T{1}); | |||
uvw.y() = T{1} - uvw.z(); | |||
return {uvw, 1}; | |||
} | |||
return {uvw, -1}; | |||
} | |||
template <class T> | |||
[[nodiscard]] inline constexpr std::tuple<point<T, 3>, int> closest_feature(const triangle<T, 3>& tri, const point<T, 3>& p) noexcept | |||
{ | |||
return closest_feature(tri.a, tri.b, tri.c, p); | |||
} | |||
/// @} | |||
} // namespace geom | |||
#endif // ANTKEEPER_GEOM_CLOSEST_FEATURE_HPP |
@ -0,0 +1,46 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_MATH_FRACT_HPP | |||
#define ANTKEEPER_MATH_FRACT_HPP | |||
#include <cmath> | |||
#include <concepts> | |||
namespace math { | |||
/** | |||
* Returns the fractional part of a floating-point number. | |||
* | |||
* @tparam T Floating-point type. | |||
* | |||
* @param x Floating-point number. | |||
* | |||
* @return Fractional part of @p x. | |||
*/ | |||
template <std::floating_point T> | |||
[[nodiscard]] inline T fract(T x) | |||
{ | |||
T i; | |||
return std::modf(x, &i); | |||
} | |||
} // namespace math | |||
#endif // ANTKEEPER_MATH_FRACT_HPP |
@ -0,0 +1,111 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include <engine/physics/kinematics/colliders/mesh-collider.hpp> | |||
#include <engine/debug/log.hpp> | |||
#include <engine/geom/intersection.hpp> | |||
#include <limits> | |||
namespace physics { | |||
mesh_collider::mesh_collider(std::shared_ptr<mesh_type> mesh) | |||
{ | |||
set_mesh(mesh); | |||
} | |||
void mesh_collider::set_mesh(std::shared_ptr<mesh_type> mesh) | |||
{ | |||
m_mesh = mesh; | |||
if (m_mesh) | |||
{ | |||
m_vertex_positions = &m_mesh->vertices().attributes().at<math::fvec3>("position"); | |||
} | |||
else | |||
{ | |||
m_vertex_positions = nullptr; | |||
} | |||
rebuild_bvh(); | |||
} | |||
void mesh_collider::rebuild_bvh() | |||
{ | |||
if (m_mesh) | |||
{ | |||
m_bvh.build(*m_mesh); | |||
} | |||
else | |||
{ | |||
m_bvh.clear(); | |||
} | |||
} | |||
std::optional<std::tuple<float, std::uint32_t>> mesh_collider::intersection(const math::transform<float>& mesh_transform, const geom::ray<float, 3>& ray) const | |||
{ | |||
// Transform ray into mesh space | |||
const auto inv_mesh_transform = math::inverse(mesh_transform); | |||
const geom::ray<float, 3> mesh_space_ray = | |||
{ | |||
inv_mesh_transform * ray.origin, | |||
inv_mesh_transform.rotation * ray.direction | |||
}; | |||
std::size_t box_hit_count = 0; | |||
std::size_t triangle_hit_count = 0; | |||
float nearest_face_distance = std::numeric_limits<float>::infinity(); | |||
std::uint32_t nearest_face_index; | |||
m_bvh.visit | |||
( | |||
mesh_space_ray, | |||
[&](std::uint32_t index) | |||
{ | |||
++box_hit_count; | |||
geom::brep_face* face = m_mesh->faces()[index]; | |||
auto loop = face->loops().begin(); | |||
const auto& a = (*m_vertex_positions)[loop->vertex()->index()]; | |||
const auto& b = (*m_vertex_positions)[(++loop)->vertex()->index()]; | |||
const auto& c = (*m_vertex_positions)[(++loop)->vertex()->index()]; | |||
if (auto intersection = geom::intersection(mesh_space_ray, a, b, c)) | |||
{ | |||
++triangle_hit_count; | |||
float t = std::get<0>(*intersection); | |||
if (t < nearest_face_distance) | |||
{ | |||
nearest_face_distance = t; | |||
nearest_face_index = index; | |||
} | |||
} | |||
} | |||
); | |||
debug::log::info("mesh collider intersection test:\n\tboxes hit: {}\n\ttriangles hit: {}", box_hit_count, triangle_hit_count); | |||
if (!triangle_hit_count) | |||
{ | |||
return std::nullopt; | |||
} | |||
return std::make_tuple(nearest_face_distance, nearest_face_index); | |||
} | |||
} // namespace physics |
@ -0,0 +1,102 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_PHYSICS_MESH_COLLIDER_HPP | |||
#define ANTKEEPER_PHYSICS_MESH_COLLIDER_HPP | |||
#include <engine/physics/kinematics/collider.hpp> | |||
#include <engine/geom/brep/brep-mesh.hpp> | |||
#include <engine/geom/bvh/bvh.hpp> | |||
#include <engine/math/vector.hpp> | |||
#include <engine/geom/primitives/ray.hpp> | |||
#include <engine/math/transform.hpp> | |||
#include <memory> | |||
#include <optional> | |||
namespace physics { | |||
/** | |||
* Mesh collision object. | |||
*/ | |||
class mesh_collider: public collider | |||
{ | |||
public: | |||
/// Collision mesh type. | |||
using mesh_type = geom::brep_mesh; | |||
/// Bounding volume hierarchy type. | |||
using bvh_type = geom::bvh; | |||
[[nodiscard]] inline constexpr collider_type type() const noexcept override | |||
{ | |||
return collider_type::mesh; | |||
} | |||
/** | |||
* Constructs a mesh collider from a mesh. | |||
* | |||
* @param mesh Collision mesh. | |||
* | |||
* @warning @p mesh must contain the math::fvec3 vertex attribute "position". | |||
* @warning @p mesh must be a triangle mesh. | |||
*/ | |||
explicit mesh_collider(std::shared_ptr<mesh_type> mesh); | |||
/// Constructs an empty mesh collider. | |||
constexpr mesh_collider() noexcept = default; | |||
/** | |||
* Sets the collider's mesh. | |||
* | |||
* @param mesh Collision mesh. | |||
* | |||
* @warning @p mesh must contain the math::fvec3 vertex attribute "position". | |||
* @warning @p mesh must be a triangle mesh. | |||
*/ | |||
void set_mesh(std::shared_ptr<mesh_type> mesh); | |||
/// Returns the collision mesh. | |||
[[nodiscard]] inline constexpr const std::shared_ptr<mesh_type>& get_mesh() const noexcept | |||
{ | |||
return m_mesh; | |||
} | |||
/// Returns the BVH of the collision mesh faces. | |||
[[nodiscard]] inline constexpr const bvh_type& get_bvh() const noexcept | |||
{ | |||
return m_bvh; | |||
} | |||
/// Rebuilds the BVH of the collision mesh faces. | |||
void rebuild_bvh(); | |||
/** | |||
* | |||
*/ | |||
[[nodiscard]] std::optional<std::tuple<float, std::uint32_t>> intersection(const math::transform<float>& mesh_transform, const geom::ray<float, 3>& ray) const; | |||
private: | |||
std::shared_ptr<mesh_type> m_mesh; | |||
const geom::brep_attribute<math::fvec3>* m_vertex_positions{}; | |||
bvh_type m_bvh; | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_MESH_COLLIDER_HPP |
@ -0,0 +1,48 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include <engine/physics/kinematics/friction.hpp> | |||
#include <algorithm> | |||
namespace physics { | |||
float combine_friction(float a, float b, friction_combine_mode mode) noexcept | |||
{ | |||
switch (mode) | |||
{ | |||
case friction_combine_mode::average: | |||
return (a + b) * 0.5f; | |||
case friction_combine_mode::minimum: | |||
return std::min(a, b); | |||
case friction_combine_mode::multiply: | |||
return a * b; | |||
case friction_combine_mode::maximum: | |||
return std::max(a, b); | |||
default: | |||
break; | |||
} | |||
return 0.0f; | |||
} | |||
} // namespace physics |
@ -0,0 +1,48 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include <engine/physics/kinematics/restitution.hpp> | |||
#include <algorithm> | |||
namespace physics { | |||
float combine_restitution(float a, float b, restitution_combine_mode mode) noexcept | |||
{ | |||
switch (mode) | |||
{ | |||
case restitution_combine_mode::average: | |||
return (a + b) * 0.5f; | |||
case restitution_combine_mode::minimum: | |||
return std::min(a, b); | |||
case restitution_combine_mode::multiply: | |||
return a * b; | |||
case restitution_combine_mode::maximum: | |||
return std::max(a, b); | |||
default: | |||
break; | |||
} | |||
return 0.0f; | |||
} | |||
} // namespace physics |
@ -0,0 +1,35 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_GAME_ALLOMETRIC_GROWTH_COMPONENT_HPP | |||
#define ANTKEEPER_GAME_ALLOMETRIC_GROWTH_COMPONENT_HPP | |||
#include <engine/animation/bone.hpp> | |||
#include <unordered_map> | |||
/** | |||
* Growth component with seperable rates for different body parts. | |||
*/ | |||
struct allometric_growth_component | |||
{ | |||
/// Growth rates of each bone. | |||
std::unordered_map<bone_index_type, float> rates; | |||
}; | |||
#endif // ANTKEEPER_GAME_ALLOMETRIC_GROWTH_COMPONENT_HPP |
@ -0,0 +1,32 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_GAME_ANT_GENOME_COMPONENT_HPP | |||
#define ANTKEEPER_GAME_ANT_GENOME_COMPONENT_HPP | |||
#include "game/ant/ant-genome.hpp" | |||
#include <memory> | |||
struct ant_genome_component | |||
{ | |||
/// Shared pointer to the ant genome. | |||
std::shared_ptr<ant_genome> genome; | |||
}; | |||
#endif // ANTKEEPER_GAME_ANT_GENOME_COMPONENT_HPP |
@ -0,0 +1,34 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_CONTACT_PHEROMONE_COMPONENT_HPP | |||
#define ANTKEEPER_CONTACT_PHEROMONE_COMPONENT_HPP | |||
#include <cstdint> | |||
/** | |||
* Pheromones that coat an exoskeleton, providing short-range chemical communication. | |||
*/ | |||
struct contact_pheromone_component | |||
{ | |||
/// Bit mask representing a cuticular hydrocarbon (CHC) profile. | |||
std::uint32_t profile{}; | |||
}; | |||
#endif // ANTKEEPER_CONTACT_PHEROMONE_COMPONENT_HPP |
@ -0,0 +1,41 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_GAME_EGG_COMPONENT_HPP | |||
#define ANTKEEPER_GAME_EGG_COMPONENT_HPP | |||
#include <engine/render/model.hpp> | |||
#include <memory> | |||
/** | |||
* | |||
*/ | |||
struct egg_component | |||
{ | |||
/// Duration of the incubation period, in seconds. | |||
float incubation_period{}; | |||
/// Elapsed time the egg has been in incubation, in seconds. | |||
float elapsed_incubation_time{}; | |||
/// Model of the larval form. | |||
std::shared_ptr<render::model> larva_model; | |||
}; | |||
#endif // ANTKEEPER_GAME_EGG_COMPONENT_HPP |
@ -0,0 +1,32 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_GAME_ISOMETRIC_GROWTH_COMPONENT_HPP | |||
#define ANTKEEPER_GAME_ISOMETRIC_GROWTH_COMPONENT_HPP | |||
/** | |||
* Growth component which scales all body parts equally. | |||
*/ | |||
struct isometric_growth_component | |||
{ | |||
/// Growth rate. | |||
float rate{}; | |||
}; | |||
#endif // ANTKEEPER_GAME_ISOMETRIC_GROWTH_COMPONENT_HPP |
@ -0,0 +1,41 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_GAME_NAVMESH_AGENT_COMPONENT_HPP | |||
#define ANTKEEPER_GAME_NAVMESH_AGENT_COMPONENT_HPP | |||
#include <engine/math/vector.hpp> | |||
#include <engine/geom/brep/brep-mesh.hpp> | |||
/** | |||
* | |||
*/ | |||
struct navmesh_agent_component | |||
{ | |||
/// Pointer to the current mesh through which the agent is navigating. | |||
geom::brep_mesh* mesh{}; | |||
/// Pointer to the current mesh face on which the agent is located. | |||
geom::brep_face* face{}; | |||
/// Smooth interpolated surface normal at the agent position. | |||
math::fvec3 surface_normal{}; | |||
}; | |||
#endif // ANTKEEPER_GAME_NAVMESH_AGENT_COMPONENT_HPP |
@ -0,0 +1,85 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_GAME_ORBIT_CAMERA_COMPONENT_HPP | |||
#define ANTKEEPER_GAME_ORBIT_CAMERA_COMPONENT_HPP | |||
#include <engine/entity/id.hpp> | |||
#include <engine/math/vector.hpp> | |||
#include <engine/math/quaternion.hpp> | |||
#include <engine/math/angles.hpp> | |||
struct orbit_camera_component | |||
{ | |||
/// Entity ID of the subject. | |||
entity::id subject_eid{entt::null}; | |||
/// Height of the view frustum at the near clipping distance. | |||
double near_focal_plane_height{1.0f}; | |||
/// Height of the view frustum at the far clipping distance. | |||
double far_focal_plane_height{50.0f}; | |||
/// Horizontal FoV at maximum zoom. | |||
double near_hfov{math::radians(90.0)}; | |||
/// Horizontal FoV at minimum zoom. | |||
double far_hfov{math::radians(45.0)}; | |||
/// Yaw angle of the camera, in radians. | |||
double yaw{}; | |||
/// Pitch angle of the camera, in radians. | |||
double pitch{}; | |||
/// Zoom factor, on `[0, 1]`. | |||
double zoom{}; | |||
/// Horizontal FoV of the camera, in radians. | |||
double hfov{}; | |||
/// Vertical FoV of the camera, in radians. | |||
double vfov{}; | |||
/// Position of the focal point, relative to the subject. | |||
math::dvec3 focal_point{}; | |||
/// Distance to the focal plane. | |||
double focal_distance{}; | |||
/// Width of the view frustum at the focal distance. | |||
double focal_plane_width{}; | |||
/// Height of the view frustum at the focal distance. | |||
double focal_plane_height{}; | |||
/// Yaw rotation quaternion. | |||
math::dquat yaw_rotation{math::dquat::identity()}; | |||
/// Pitch rotation quaternion. | |||
math::dquat pitch_rotation{math::dquat::identity()}; | |||
/// Pitch and yaw rotation quaternion. | |||
math::dquat orientation{math::dquat::identity()}; | |||
math::dquat up_rotation{math::dquat::identity()}; | |||
}; | |||
#endif // ANTKEEPER_GAME_ORBIT_CAMERA_COMPONENT_HPP |
@ -0,0 +1,65 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_GAME_OVARY_COMPONENT_HPP | |||
#define ANTKEEPER_GAME_OVARY_COMPONENT_HPP | |||
#include <engine/animation/bone.hpp> | |||
#include <engine/geom/primitives/line-segment.hpp> | |||
#include <engine/entity/id.hpp> | |||
#include <cstdint> | |||
#include <memory> | |||
/** | |||
* | |||
*/ | |||
struct ovary_component | |||
{ | |||
/// Maximum number of concurrent eggs. | |||
std::uint16_t egg_capacity{}; | |||
/// Number of fully-developed eggs. | |||
std::uint16_t egg_count{}; | |||
/// Duration required to produce an egg, in seconds. | |||
float egg_production_duration{}; | |||
/// Elapsed time the current egg has been in production, in seconds. | |||
float elapsed_egg_production_time{}; | |||
/// Duration required to lay an egg, in seconds. | |||
float oviposition_duration{}; | |||
/// Elapsed time the current egg has been traveling down the common oviduct, in seconds. | |||
float elapsed_oviposition_time{}; | |||
/// `true` if currently ovipositing an egg, `false` otherwise. | |||
bool ovipositing{}; | |||
/// Bone of the ovipositor. | |||
bone_index_type ovipositor_bone{}; | |||
/// Path along which eggs travel while being oviposited, relative to the ovipositor bone. | |||
geom::line_segment<float, 3> oviposition_path{}; | |||
/// Entity ID of the egg currently in the ovipositor (if any). | |||
entity::id ovipositor_egg_eid{entt::null}; | |||
}; | |||
#endif // ANTKEEPER_GAME_OVARY_COMPONENT_HPP |
@ -0,0 +1,37 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_GAME_POSE_COMPONENT_HPP | |||
#define ANTKEEPER_GAME_POSE_COMPONENT_HPP | |||
#include <engine/animation/pose.hpp> | |||
/** | |||
* | |||
*/ | |||
struct pose_component | |||
{ | |||
/// Pose of the current state. | |||
pose current_pose; | |||
/// Pose of the previous state | |||
pose previous_pose; | |||
}; | |||
#endif // ANTKEEPER_GAME_POSE_COMPONENT_HPP |
@ -0,0 +1,232 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "game/controls.hpp" | |||
#include "game/components/ant-caste-component.hpp" | |||
#include "game/components/rigid-body-component.hpp" | |||
#include "game/components/legged-locomotion-component.hpp" | |||
#include "game/components/ovary-component.hpp" | |||
#include <engine/math/interpolation.hpp> | |||
#include <engine/debug/log.hpp> | |||
namespace { | |||
/** | |||
* Updates the locomotive speed of the controlled ant. | |||
* | |||
* @param ctx Game context. | |||
*/ | |||
void update_controlled_ant_speed(::game& ctx) | |||
{ | |||
if (ctx.controlled_ant_eid == entt::null) | |||
{ | |||
return; | |||
} | |||
// Get phenome of controlled ant caste | |||
const auto& caste_phenome = *ctx.entity_registry->get<::ant_caste_component>(ctx.controlled_ant_eid).phenome; | |||
// Determine locomotive speed | |||
float locomotive_speed; | |||
if (ctx.ant_move_slow_action.is_active()) | |||
{ | |||
// Interpolate locomotive speed between walking and creeping | |||
locomotive_speed = math::lerp(caste_phenome.legs->walking_speed, caste_phenome.legs->creeping_speed, ctx.ant_move_slow_action.get_input_value()); | |||
} | |||
else if (ctx.ant_move_fast_action.is_active()) | |||
{ | |||
// Interpolate locomotive speed between walking and running | |||
locomotive_speed = math::lerp(caste_phenome.legs->walking_speed, caste_phenome.legs->running_speed, ctx.ant_move_fast_action.get_input_value()); | |||
} | |||
else | |||
{ | |||
// Set locomotive speed to walking speed | |||
locomotive_speed = caste_phenome.legs->walking_speed; | |||
} | |||
// Scale locomotive speed by move ant forward action input value | |||
locomotive_speed *= ctx.ant_move_forward_action.get_input_value(); | |||
// Scale locomotive speed by scale of controlled ant | |||
locomotive_speed *= ctx.entity_registry->get<rigid_body_component>(ctx.controlled_ant_eid).body->get_transform().scale.x(); | |||
// Update speed of legged locomotion component | |||
ctx.entity_registry->patch<::legged_locomotion_component> | |||
( | |||
ctx.controlled_ant_eid, | |||
[&](auto& component) | |||
{ | |||
component.speed = locomotive_speed; | |||
} | |||
); | |||
} | |||
/** | |||
* Turns the controlled ant. | |||
* | |||
* @param ctx Game context. | |||
* @param scale Angular velocity scale. | |||
*/ | |||
void turn_controlled_ant(::game& ctx, float scale) | |||
{ | |||
if (ctx.controlled_ant_eid == entt::null) | |||
{ | |||
return; | |||
} | |||
ctx.entity_registry->patch<::legged_locomotion_component> | |||
( | |||
ctx.controlled_ant_eid, | |||
[&](auto& component) | |||
{ | |||
component.angular_velocity = math::radians(120.0f) * scale; | |||
} | |||
); | |||
} | |||
} | |||
void setup_ant_controls(::game& ctx) | |||
{ | |||
// Ant move forward | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.ant_move_forward_action.get_active_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
update_controlled_ant_speed(ctx); | |||
} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.ant_move_forward_action.get_deactivated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
update_controlled_ant_speed(ctx); | |||
} | |||
) | |||
); | |||
// Ant move back | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.ant_move_back_action.get_active_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
update_controlled_ant_speed(ctx); | |||
} | |||
) | |||
); | |||
// Ant move left | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.ant_move_left_action.get_active_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
turn_controlled_ant(ctx, event.input_value); | |||
} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.ant_move_left_action.get_deactivated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
turn_controlled_ant(ctx, 0.0f); | |||
} | |||
) | |||
); | |||
// Ant move right | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.ant_move_right_action.get_active_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
turn_controlled_ant(ctx, -event.input_value); | |||
} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.ant_move_right_action.get_deactivated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
turn_controlled_ant(ctx, 0.0f); | |||
} | |||
) | |||
); | |||
// Ant oviposit | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.ant_oviposit_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
if (ctx.controlled_ant_eid == entt::null) | |||
{ | |||
return; | |||
} | |||
if (auto ovary_component = ctx.entity_registry->try_get<ovary_component>(ctx.controlled_ant_eid)) | |||
{ | |||
ovary_component->ovipositing = true; | |||
} | |||
} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.ant_oviposit_action.get_deactivated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
if (ctx.controlled_ant_eid == entt::null) | |||
{ | |||
return; | |||
} | |||
if (auto ovary_component = ctx.entity_registry->try_get<ovary_component>(ctx.controlled_ant_eid)) | |||
{ | |||
ovary_component->ovipositing = false; | |||
} | |||
} | |||
) | |||
); | |||
} | |||
void enable_ant_controls(::game& ctx) | |||
{ | |||
ctx.ant_action_map.enable(); | |||
} | |||
void disable_ant_controls(::game& ctx) | |||
{ | |||
ctx.ant_action_map.disable(); | |||
ctx.ant_action_map.reset(); | |||
} |
@ -0,0 +1,397 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "game/controls.hpp" | |||
#include "game/components/orbit-camera-component.hpp" | |||
#include <engine/debug/log.hpp> | |||
namespace { | |||
/* | |||
void orbit_camera(::game& ctx, float yaw_factor, float pitch_factor) | |||
{ | |||
if (ctx.active_camera_eid == entt::null) | |||
{ | |||
return; | |||
} | |||
auto& orbit_cam = ctx.entity_registry->get<orbit_camera_component>(ctx.active_camera_eid); | |||
// Adjust yaw and pitch angles according to mouse motion | |||
orbit_cam.yaw -= ctx.mouse_pan_factor * static_cast<double>(event.difference.x()); | |||
orbit_cam.pitch += ctx.mouse_tilt_factor * static_cast<double>(event.difference.y()); | |||
// Limit pitch | |||
orbit_cam.pitch = std::min(math::half_pi<double>, std::max(-math::half_pi<double>, orbit_cam.pitch)); | |||
} | |||
*/ | |||
void handle_mouse_motion(::game& ctx, const input::mouse_moved_event& event) | |||
{ | |||
if (ctx.active_camera_eid == entt::null) | |||
{ | |||
return; | |||
} | |||
auto& orbit_cam = ctx.entity_registry->get<orbit_camera_component>(ctx.active_camera_eid); | |||
// Rotate camera | |||
if (ctx.camera_mouse_look_action.is_active()) | |||
{ | |||
// Adjust yaw and pitch angles according to mouse motion | |||
orbit_cam.yaw -= ctx.mouse_pan_factor * static_cast<double>(event.difference.x()); | |||
orbit_cam.pitch += ctx.mouse_tilt_factor * static_cast<double>(event.difference.y()); | |||
// Limit pitch | |||
orbit_cam.pitch = std::min(math::half_pi<double>, std::max(-math::half_pi<double>, orbit_cam.pitch)); | |||
} | |||
// Zoom camera | |||
if (ctx.camera_mouse_zoom_action.is_active()) | |||
{ | |||
// Adjust zoom factor | |||
orbit_cam.zoom -= static_cast<double>(event.difference.y()) / static_cast<double>(ctx.window->get_viewport_size().y()); | |||
// Limit zoom factor | |||
orbit_cam.zoom = std::min<double>(std::max<double>(orbit_cam.zoom, 0.0), 1.0); | |||
} | |||
} | |||
void load_camera_preset(::game& ctx,std::uint8_t index) | |||
{ | |||
} | |||
void save_camera_preset(::game& ctx,std::uint8_t index) | |||
{ | |||
} | |||
void step_camera_zoom(::game& ctx, double scale) | |||
{ | |||
if (ctx.active_camera_eid == entt::null) | |||
{ | |||
return; | |||
} | |||
auto& orbit_cam = ctx.entity_registry->get<orbit_camera_component>(ctx.active_camera_eid); | |||
// Step zoom factor | |||
constexpr double zoom_step = 1.0 / 6.0; | |||
orbit_cam.zoom += zoom_step * scale; | |||
// Limit zoom factor | |||
orbit_cam.zoom = std::min<double>(std::max<double>(orbit_cam.zoom, 0.0), 1.0); | |||
} | |||
void update_relative_mouse_mode(::game& ctx) | |||
{ | |||
if (ctx.camera_mouse_look_action.is_active() || | |||
ctx.camera_mouse_drag_action.is_active() || | |||
ctx.camera_mouse_zoom_action.is_active()) | |||
{ | |||
ctx.input_manager->set_relative_mouse_mode(true); | |||
} | |||
else | |||
{ | |||
ctx.input_manager->set_relative_mouse_mode(false); | |||
} | |||
} | |||
void load_or_save_camera_preset(::game& ctx, std::uint8_t index) | |||
{ | |||
if (ctx.camera_save_preset_action.is_active()) | |||
{ | |||
save_camera_preset(ctx, index); | |||
} | |||
else | |||
{ | |||
load_camera_preset(ctx, index); | |||
} | |||
} | |||
} | |||
void setup_camera_controls(::game& ctx) | |||
{ | |||
// Camera mouse motion | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.input_manager->get_event_dispatcher().subscribe<input::mouse_moved_event> | |||
( | |||
[&](const auto& event) | |||
{ | |||
if (ctx.camera_action_map.is_enabled()) | |||
{ | |||
handle_mouse_motion(ctx, event); | |||
} | |||
} | |||
) | |||
); | |||
// Camera mouse pick | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_mouse_pick_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
} | |||
) | |||
); | |||
// Camera mouse look | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_mouse_look_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
update_relative_mouse_mode(ctx); | |||
} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_mouse_look_action.get_deactivated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
update_relative_mouse_mode(ctx); | |||
} | |||
) | |||
); | |||
// Camera mouse drag | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_mouse_drag_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
update_relative_mouse_mode(ctx); | |||
/* | |||
mouse_grip = ctx.toggle_mouse_grip ? !mouse_grip : true; | |||
if (mouse_grip) | |||
{ | |||
const auto& mouse_position = (*ctx.input_manager->get_mice().begin())->get_position(); | |||
// Cast ray to plane | |||
const auto mouse_ray = get_mouse_ray(mouse_position); | |||
const auto intersection = geom::intersection(mouse_ray, mouse_grip_plane); | |||
if (intersection) | |||
{ | |||
mouse_grip_point = mouse_ray.origin + mouse_ray.direction * (*intersection); | |||
} | |||
} | |||
ctx.input_manager->set_relative_mouse_mode(mouse_look || mouse_grip || mouse_zoom); | |||
*/ | |||
} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_mouse_drag_action.get_deactivated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
update_relative_mouse_mode(ctx); | |||
} | |||
) | |||
); | |||
// Camera mouse zoom | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_mouse_zoom_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
update_relative_mouse_mode(ctx); | |||
} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_mouse_zoom_action.get_deactivated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
update_relative_mouse_mode(ctx); | |||
} | |||
) | |||
); | |||
// Camera zoom in | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_zoom_in_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
step_camera_zoom(ctx, 1.0 * static_cast<double>(ctx.camera_zoom_in_action.get_input_value())); | |||
} | |||
) | |||
); | |||
// Camera zoom out | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_zoom_out_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
step_camera_zoom(ctx, -1.0 * static_cast<double>(ctx.camera_zoom_out_action.get_input_value())); | |||
} | |||
) | |||
); | |||
// Camera orbit left | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_orbit_left_action.get_active_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
} | |||
) | |||
); | |||
// Camera orbit right | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_orbit_right_action.get_active_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
} | |||
) | |||
); | |||
// Camera orbit up | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_orbit_up_action.get_active_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
} | |||
) | |||
); | |||
// Camera orbit down | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_orbit_down_action.get_active_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
} | |||
) | |||
); | |||
// Camera presets | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_preset_1_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) {load_or_save_camera_preset(ctx, 0);} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_preset_2_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) {load_or_save_camera_preset(ctx, 1);} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_preset_3_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) {load_or_save_camera_preset(ctx, 2);} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_preset_4_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) {load_or_save_camera_preset(ctx, 3);} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_preset_5_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) {load_or_save_camera_preset(ctx, 4);} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_preset_6_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) {load_or_save_camera_preset(ctx, 5);} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_preset_7_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) {load_or_save_camera_preset(ctx, 6);} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_preset_8_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) {load_or_save_camera_preset(ctx, 7);} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_preset_9_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) {load_or_save_camera_preset(ctx, 8);} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.camera_preset_10_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) {load_or_save_camera_preset(ctx, 9);} | |||
) | |||
); | |||
} | |||
void enable_camera_controls(::game& ctx) | |||
{ | |||
ctx.camera_action_map.enable(); | |||
} | |||
void disable_camera_controls(::game& ctx) | |||
{ | |||
ctx.camera_action_map.disable(); | |||
ctx.camera_action_map.reset(); | |||
} |
@ -0,0 +1,93 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "game/controls.hpp" | |||
#include "game/systems/astronomy-system.hpp" | |||
#include "game/world.hpp" | |||
void setup_debug_controls(::game& ctx) | |||
{ | |||
// Toggle debug UI | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.toggle_debug_ui_action.get_activated_channel().subscribe | |||
( | |||
[&](const auto& event) | |||
{ | |||
ctx.debug_ui_visible = !ctx.debug_ui_visible; | |||
if (ctx.debug_ui_visible) | |||
{ | |||
ctx.ui_scene->add_object(*ctx.frame_time_text); | |||
} | |||
else | |||
{ | |||
ctx.ui_scene->remove_object(*ctx.frame_time_text); | |||
} | |||
} | |||
) | |||
); | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.input_manager->get_event_dispatcher().subscribe<input::mouse_moved_event> | |||
( | |||
[&](const auto& event) | |||
{ | |||
if (ctx.adjust_time_action.is_active()) | |||
{ | |||
const double sensitivity = 1.0 / static_cast<double>(ctx.window->get_viewport_size().x()); | |||
const double t = ctx.astronomy_system->get_time(); | |||
::world::set_time(ctx, t + static_cast<double>(event.difference.x()) * sensitivity); | |||
} | |||
if (ctx.adjust_exposure_action.is_active()) | |||
{ | |||
scene::camera* camera{}; | |||
if (ctx.active_scene == ctx.surface_scene.get()) | |||
{ | |||
camera = ctx.surface_camera.get(); | |||
} | |||
else if (ctx.active_scene == ctx.underground_scene.get()) | |||
{ | |||
camera = ctx.underground_camera.get(); | |||
} | |||
if (camera) | |||
{ | |||
const float sensitivity = 8.0f / static_cast<float>(ctx.window->get_viewport_size().y()); | |||
ctx.surface_camera->set_exposure_value(ctx.surface_camera->get_exposure_value() + static_cast<float>(event.difference.y()) * sensitivity); | |||
} | |||
} | |||
} | |||
) | |||
); | |||
} | |||
void enable_debug_controls(::game& ctx) | |||
{ | |||
ctx.debug_action_map.enable(); | |||
} | |||
void disable_debug_controls(::game& ctx) | |||
{ | |||
ctx.debug_action_map.disable(); | |||
ctx.toggle_debug_ui_action.reset(); | |||
ctx.adjust_exposure_action.reset(); | |||
ctx.adjust_time_action.reset(); | |||
} |
@ -0,0 +1,227 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "game/controls.hpp" | |||
#include "game/menu.hpp" | |||
#include <engine/config.hpp> | |||
void setup_menu_controls(::game& ctx) | |||
{ | |||
// Setup menu controls | |||
ctx.menu_action_subscriptions.emplace_back | |||
( | |||
ctx.menu_up_action.get_activated_channel().subscribe | |||
( | |||
[&ctx](const auto& event) | |||
{ | |||
--(*ctx.menu_item_index); | |||
if (*ctx.menu_item_index < 0) | |||
*ctx.menu_item_index = static_cast<int>(ctx.menu_item_texts.size()) - 1; | |||
::menu::update_text_color(ctx); | |||
} | |||
) | |||
); | |||
ctx.menu_action_subscriptions.emplace_back | |||
( | |||
ctx.menu_down_action.get_activated_channel().subscribe | |||
( | |||
[&ctx](const auto& event) | |||
{ | |||
++(*ctx.menu_item_index); | |||
if (*ctx.menu_item_index >= ctx.menu_item_texts.size()) | |||
*ctx.menu_item_index = 0; | |||
::menu::update_text_color(ctx); | |||
} | |||
) | |||
); | |||
ctx.menu_action_subscriptions.emplace_back | |||
( | |||
ctx.menu_left_action.get_activated_channel().subscribe | |||
( | |||
[&ctx](const auto& event) | |||
{ | |||
auto callback = ctx.menu_left_callbacks[*ctx.menu_item_index]; | |||
if (callback != nullptr) | |||
callback(); | |||
} | |||
) | |||
); | |||
ctx.menu_action_subscriptions.emplace_back | |||
( | |||
ctx.menu_right_action.get_activated_channel().subscribe | |||
( | |||
[&ctx](const auto& event) | |||
{ | |||
auto callback = ctx.menu_right_callbacks[*ctx.menu_item_index]; | |||
if (callback != nullptr) | |||
callback(); | |||
} | |||
) | |||
); | |||
ctx.menu_action_subscriptions.emplace_back | |||
( | |||
ctx.menu_select_action.get_activated_channel().subscribe | |||
( | |||
[&ctx](const auto& event) | |||
{ | |||
const auto& callback = ctx.menu_select_callbacks[*ctx.menu_item_index]; | |||
if (callback != nullptr) | |||
callback(); | |||
} | |||
) | |||
); | |||
ctx.menu_action_subscriptions.emplace_back | |||
( | |||
ctx.menu_back_action.get_activated_channel().subscribe | |||
( | |||
[&ctx](const auto& event) | |||
{ | |||
if (ctx.menu_back_callback != nullptr) | |||
ctx.menu_back_callback(); | |||
} | |||
) | |||
); | |||
// Set activation threshold for menu navigation controls to mitigate drifting gamepad axes | |||
auto menu_action_threshold = [](float x) -> bool | |||
{ | |||
return x > 0.5f; | |||
}; | |||
ctx.menu_up_action.set_threshold_function(menu_action_threshold); | |||
ctx.menu_down_action.set_threshold_function(menu_action_threshold); | |||
ctx.menu_left_action.set_threshold_function(menu_action_threshold); | |||
ctx.menu_right_action.set_threshold_function(menu_action_threshold); | |||
} | |||
void enable_menu_controls(::game& ctx) | |||
{ | |||
ctx.menu_action_map.enable(); | |||
// Function to select menu item at mouse position | |||
auto select_menu_item = [&ctx](const math::fvec2& mouse_position) -> bool | |||
{ | |||
const float padding = config::menu_mouseover_padding * ctx.menu_font.get_font_metrics().size; | |||
for (std::size_t i = 0; i < ctx.menu_item_texts.size(); ++i) | |||
{ | |||
auto [name, value] = ctx.menu_item_texts[i]; | |||
const auto& name_bounds = name->get_bounds(); | |||
float min_x = name_bounds.min.x(); | |||
float min_y = name_bounds.min.y(); | |||
float max_x = name_bounds.max.x(); | |||
float max_y = name_bounds.max.y(); | |||
if (value) | |||
{ | |||
const auto& value_bounds = value->get_bounds(); | |||
min_x = std::min<float>(min_x, value_bounds.min.x()); | |||
min_y = std::min<float>(min_y, value_bounds.min.y()); | |||
max_x = std::max<float>(max_x, value_bounds.max.x()); | |||
max_y = std::max<float>(max_y, value_bounds.max.y()); | |||
} | |||
min_x -= padding; | |||
min_y -= padding; | |||
max_x += padding; | |||
max_y += padding; | |||
const auto& viewport = ctx.window->get_viewport_size(); | |||
const float x = mouse_position.x(); | |||
const float y = static_cast<float>((viewport[1] - mouse_position.y() + 1)); | |||
if (x >= min_x && x <= max_x) | |||
{ | |||
if (y >= min_y && y <= max_y) | |||
{ | |||
*ctx.menu_item_index = static_cast<int>(i); | |||
::menu::update_text_color(ctx); | |||
return true; | |||
} | |||
} | |||
} | |||
return false; | |||
}; | |||
// Enable menu mouse tracking | |||
ctx.menu_mouse_subscriptions.clear(); | |||
ctx.menu_mouse_subscriptions.emplace_back | |||
( | |||
ctx.input_manager->get_event_dispatcher().subscribe<input::mouse_moved_event> | |||
( | |||
[&ctx, select_menu_item](const auto& event) | |||
{ | |||
// Select menu item at mouse position (if any) | |||
select_menu_item(math::fvec2(event.position)); | |||
} | |||
) | |||
); | |||
ctx.menu_mouse_subscriptions.emplace_back | |||
( | |||
ctx.input_manager->get_event_dispatcher().subscribe<input::mouse_button_pressed_event> | |||
( | |||
[&ctx, select_menu_item](const auto& event) | |||
{ | |||
// Select menu item at mouse position (if any) | |||
if (select_menu_item(math::fvec2(event.position))) | |||
{ | |||
// Determine appropriate menu item callback | |||
auto callback = ctx.menu_select_callbacks[*ctx.menu_item_index]; | |||
if (event.button == input::mouse_button::left) | |||
{ | |||
if (ctx.menu_left_callbacks[*ctx.menu_item_index]) | |||
{ | |||
callback = ctx.menu_left_callbacks[*ctx.menu_item_index]; | |||
} | |||
} | |||
else if (event.button == input::mouse_button::right) | |||
{ | |||
if (ctx.menu_right_callbacks[*ctx.menu_item_index]) | |||
{ | |||
callback = ctx.menu_right_callbacks[*ctx.menu_item_index]; | |||
} | |||
} | |||
// Invoke menu item callback | |||
if (callback) | |||
{ | |||
callback(); | |||
} | |||
} | |||
} | |||
) | |||
); | |||
} | |||
void disable_menu_controls(::game& ctx) | |||
{ | |||
ctx.menu_action_map.disable(); | |||
ctx.menu_up_action.reset(); | |||
ctx.menu_down_action.reset(); | |||
ctx.menu_left_action.reset(); | |||
ctx.menu_right_action.reset(); | |||
ctx.menu_select_action.reset(); | |||
ctx.menu_back_action.reset(); | |||
ctx.menu_modifier_action.reset(); | |||
ctx.menu_mouse_subscriptions.clear(); | |||
} |
@ -0,0 +1,60 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "game/controls.hpp" | |||
#include "game/graphics.hpp" | |||
void setup_window_controls(::game& ctx) | |||
{ | |||
// Toggle fullscreen | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.fullscreen_action.get_activated_channel().subscribe | |||
( | |||
[&ctx](const auto& event) | |||
{ | |||
ctx.window->set_fullscreen(!ctx.window->is_fullscreen()); | |||
} | |||
) | |||
); | |||
// Take screenshot | |||
ctx.event_subscriptions.emplace_back | |||
( | |||
ctx.screenshot_action.get_activated_channel().subscribe | |||
( | |||
[&ctx](const auto& event) | |||
{ | |||
::graphics::save_screenshot(ctx); | |||
} | |||
) | |||
); | |||
} | |||
void enable_window_controls(::game& ctx) | |||
{ | |||
ctx.window_action_map.enable(); | |||
} | |||
void disable_window_controls(::game& ctx) | |||
{ | |||
ctx.window_action_map.disable(); | |||
ctx.fullscreen_action.reset(); | |||
ctx.screenshot_action.reset(); | |||
} |
@ -0,0 +1,73 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "game/systems/animation-system.hpp" | |||
#include "game/components/pose-component.hpp" | |||
#include "game/components/scene-component.hpp" | |||
#include <engine/animation/bone.hpp> | |||
#include <engine/scene/skeletal-mesh.hpp> | |||
#include <engine/math/interpolation.hpp> | |||
#include <algorithm> | |||
#include <execution> | |||
animation_system::animation_system(entity::registry& registry): | |||
updatable_system(registry) | |||
{} | |||
void animation_system::update(float t, float dt) | |||
{ | |||
} | |||
void animation_system::interpolate(float alpha) | |||
{ | |||
auto pose_group = registry.group<pose_component>(entt::get<scene_component>); | |||
std::for_each | |||
( | |||
std::execution::par_unseq, | |||
pose_group.begin(), | |||
pose_group.end(), | |||
[&](auto entity_id) | |||
{ | |||
auto& pose = pose_group.get<pose_component>(entity_id); | |||
auto& scene = pose_group.get<scene_component>(entity_id); | |||
auto& skeletal_mesh = static_cast<scene::skeletal_mesh&>(*scene.object); | |||
for (std::size_t i = 0; i < skeletal_mesh.get_skeleton()->get_bone_count(); ++i) | |||
{ | |||
const auto bone_index = static_cast<bone_index_type>(i); | |||
const auto& previous_transform = pose.previous_pose.get_relative_transform(bone_index); | |||
const auto& current_transform = pose.current_pose.get_relative_transform(bone_index); | |||
// Interpolate bone pose between previous and current states | |||
bone_transform_type interpolated_transform; | |||
interpolated_transform.translation = math::lerp(previous_transform.translation, current_transform.translation, alpha); | |||
interpolated_transform.rotation = math::nlerp(previous_transform.rotation, current_transform.rotation, alpha); | |||
interpolated_transform.scale = math::lerp(previous_transform.scale, current_transform.scale, alpha); | |||
// Update skeletal mesh bone pose with interpolated transform | |||
skeletal_mesh.get_pose().set_relative_transform(static_cast<bone_index_type>(i), interpolated_transform); | |||
} | |||
// Concatenate interpolated pose | |||
skeletal_mesh.get_pose().update(); | |||
} | |||
); | |||
} | |||
@ -0,0 +1,37 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_GAME_ANIMATION_SYSTEM_HPP | |||
#define ANTKEEPER_GAME_ANIMATION_SYSTEM_HPP | |||
#include "game/systems/updatable-system.hpp" | |||
/** | |||
* | |||
*/ | |||
class animation_system: | |||
public updatable_system | |||
{ | |||
public: | |||
explicit animation_system(entity::registry& registry); | |||
void update(float t, float dt) override; | |||
void interpolate(float alpha); | |||
}; | |||
#endif // ANTKEEPER_GAME_ANIMATION_SYSTEM_HPP |
@ -0,0 +1,132 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "game/systems/reproductive-system.hpp" | |||
#include "game/components/ovary-component.hpp" | |||
#include "game/components/scene-component.hpp" | |||
#include "game/components/pose-component.hpp" | |||
#include "game/components/rigid-body-component.hpp" | |||
#include "game/components/egg-component.hpp" | |||
#include "game/components/ant-genome-component.hpp" | |||
#include <engine/math/fract.hpp> | |||
#include <engine/math/interpolation.hpp> | |||
#include <engine/scene/static-mesh.hpp> | |||
#include <engine/debug/log.hpp> | |||
#include <execution> | |||
reproductive_system::reproductive_system(entity::registry& registry): | |||
updatable_system(registry) | |||
{} | |||
void reproductive_system::update(float t, float dt) | |||
{ | |||
auto ovary_group = registry.group<ovary_component>(entt::get<ant_genome_component, rigid_body_component, scene_component, pose_component>); | |||
std::for_each | |||
( | |||
std::execution::seq, | |||
ovary_group.begin(), | |||
ovary_group.end(), | |||
[&](auto entity_id) | |||
{ | |||
auto& ovary = ovary_group.get<ovary_component>(entity_id); | |||
// Produce eggs | |||
if (ovary.egg_count < ovary.egg_capacity) | |||
{ | |||
ovary.elapsed_egg_production_time += dt * m_time_scale; | |||
if (ovary.elapsed_egg_production_time >= ovary.egg_production_duration) | |||
{ | |||
ovary.egg_count += static_cast<std::uint16_t>(ovary.elapsed_egg_production_time / ovary.egg_production_duration); | |||
ovary.egg_count = std::min(ovary.egg_count, ovary.egg_capacity); | |||
ovary.elapsed_egg_production_time = math::fract(ovary.elapsed_egg_production_time); | |||
} | |||
} | |||
// Oviposit egg | |||
if (ovary.ovipositor_egg_eid != entt::null || (ovary.ovipositing && ovary.egg_count)) | |||
{ | |||
// Get transform of ovipositor | |||
const auto& ovipositor_rigid_body = *ovary_group.get<rigid_body_component>(entity_id).body; | |||
const auto& ovipositor_pose = ovary_group.get<pose_component>(entity_id); | |||
const auto ovipositor_transform = ovipositor_rigid_body.get_transform() * ovipositor_pose.current_pose.get_absolute_transform(ovary.ovipositor_bone); | |||
// Advance oviposition time | |||
if (ovary.ovipositing) | |||
{ | |||
ovary.elapsed_oviposition_time += dt * m_time_scale; | |||
} | |||
else | |||
{ | |||
ovary.elapsed_oviposition_time -= dt * m_time_scale; | |||
ovary.elapsed_oviposition_time = std::max(0.0f, ovary.elapsed_oviposition_time); | |||
} | |||
// Determine position and orientation of egg | |||
const float t = std::min(ovary.elapsed_oviposition_time / ovary.oviposition_duration, 1.0f); | |||
auto egg_transform = ovipositor_transform; | |||
egg_transform.translation = egg_transform * math::lerp(ovary.oviposition_path.a, ovary.oviposition_path.b, t); | |||
if (ovary.ovipositor_egg_eid == entt::null) | |||
{ | |||
// Get genome of parent entity | |||
const auto& parent_genome = ovary_group.get<ant_genome_component>(entity_id); | |||
// Get scene component of ovipositing entity | |||
const auto& ovipositor_scene = ovary_group.get<scene_component>(entity_id); | |||
// Construct egg rigid body | |||
auto egg_rigid_body = std::make_unique<physics::rigid_body>(); | |||
egg_rigid_body->set_mass(0.0f); | |||
egg_rigid_body->set_transform(egg_transform); | |||
egg_rigid_body->set_previous_transform(egg_transform); | |||
// Construct egg scene object | |||
auto egg_scene_object = std::make_shared<scene::static_mesh>(parent_genome.genome->egg->phenes.front().model); | |||
// Construct egg entity | |||
ovary.ovipositor_egg_eid = registry.create(); | |||
registry.emplace<rigid_body_component>(ovary.ovipositor_egg_eid, std::move(egg_rigid_body)); | |||
registry.emplace<scene_component>(ovary.ovipositor_egg_eid, std::move(egg_scene_object), ovipositor_scene.layer_mask); | |||
registry.emplace<ant_genome_component>(ovary.ovipositor_egg_eid, parent_genome); | |||
} | |||
else | |||
{ | |||
// Update position of egg rigid body | |||
auto& egg_rigid_body = *registry.get<rigid_body_component>(ovary.ovipositor_egg_eid).body; | |||
egg_rigid_body.set_transform(egg_transform); | |||
} | |||
if (ovary.elapsed_oviposition_time >= ovary.oviposition_duration) | |||
{ | |||
// Construct egg component | |||
egg_component egg; | |||
egg.incubation_period = 5.0f; | |||
registry.emplace<egg_component>(ovary.ovipositor_egg_eid, std::move(egg)); | |||
// Oviposition complete | |||
ovary.ovipositing = false; | |||
ovary.elapsed_oviposition_time = 0.0f; | |||
--ovary.egg_count; | |||
ovary.ovipositor_egg_eid = entt::null; | |||
} | |||
} | |||
} | |||
); | |||
} |
@ -0,0 +1,49 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_GAME_REPRODUCTIVE_SYSTEM_HPP | |||
#define ANTKEEPER_GAME_REPRODUCTIVE_SYSTEM_HPP | |||
#include "game/systems/updatable-system.hpp" | |||
/** | |||
* | |||
*/ | |||
class reproductive_system: | |||
public updatable_system | |||
{ | |||
public: | |||
explicit reproductive_system(entity::registry& registry); | |||
void update(float t, float dt) override; | |||
/** | |||
* Sets the factor by which the timestep `dt` will be scaled. | |||
* | |||
* @param scale Factor by which to scale the timestep. | |||
*/ | |||
inline constexpr void set_time_scale(float scale) noexcept | |||
{ | |||
m_time_scale = scale; | |||
} | |||
private: | |||
float m_time_scale{1.0f}; | |||
}; | |||
#endif // ANTKEEPER_GAME_REPRODUCTIVE_SYSTEM_HPP |