/* * 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 . */ #include "game/ant/ant-cladogenesis.hpp" #include "game/ant/ant-genome.hpp" #include "game/ant/ant-morphogenesis.hpp" #include "game/ant/ant-phenome.hpp" #include "game/commands/commands.hpp" #include "game/components/constraint-stack-component.hpp" #include "game/components/scene-component.hpp" #include "game/components/picking-component.hpp" #include "game/components/rigid-body-component.hpp" #include "game/components/rigid-body-constraint-component.hpp" #include "game/components/steering-component.hpp" #include "game/components/terrain-component.hpp" #include "game/components/legged-locomotion-component.hpp" #include "game/components/winged-locomotion-component.hpp" #include "game/components/ik-component.hpp" #include "game/components/transform-component.hpp" #include "game/constraints/child-of-constraint.hpp" #include "game/constraints/copy-rotation-constraint.hpp" #include "game/constraints/copy-scale-constraint.hpp" #include "game/constraints/copy-transform-constraint.hpp" #include "game/constraints/copy-translation-constraint.hpp" #include "game/constraints/ease-to-constraint.hpp" #include "game/constraints/pivot-constraint.hpp" #include "game/constraints/spring-rotation-constraint.hpp" #include "game/constraints/spring-to-constraint.hpp" #include "game/constraints/spring-translation-constraint.hpp" #include "game/constraints/three-dof-constraint.hpp" #include "game/constraints/track-to-constraint.hpp" #include "game/controls.hpp" #include "game/spawn.hpp" #include "game/states/nest-selection-state.hpp" #include "game/states/pause-menu-state.hpp" #include "game/systems/astronomy-system.hpp" #include "game/systems/atmosphere-system.hpp" #include "game/systems/camera-system.hpp" #include "game/systems/collision-system.hpp" #include "game/world.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include nest_selection_state::nest_selection_state(::game& ctx): game_state(ctx) { debug::log_trace("Entering nest selection state..."); // Create world if not yet created if (ctx.entities.find("earth") == ctx.entities.end()) { // Create cosmos ::world::cosmogenesis(ctx); // Create observer ::world::create_observer(ctx); } ctx.active_ecoregion = ctx.resource_manager->load<::ecoregion>("seedy-scrub.eco"); ::world::enter_ecoregion(ctx, *ctx.active_ecoregion); debug::log_trace("Generating genome..."); std::unique_ptr genome = ant_cladogenesis(ctx.active_ecoregion->gene_pools[0], ctx.rng); debug::log_trace("Generated genome"); debug::log_trace("Building worker phenome..."); ant_phenome worker_phenome = ant_phenome(*genome, ant_caste_type::queen); debug::log_trace("Built worker phenome..."); debug::log_trace("Generating worker model..."); worker_model = ant_morphogenesis(worker_phenome); debug::log_trace("Generated worker model"); // Create floor plane auto floor_archetype = ctx.resource_manager->load("desert-scrub-plane.ent"); auto floor_eid = floor_archetype->create(*ctx.entity_registry); ctx.entity_registry->patch ( floor_eid, [](auto& component) { component.local.rotation = math::angle_axis(math::radians(3.0f), math::fvec3{1.0f, 0.0f, 0.0f}); } ); auto floor_body = std::make_unique(); auto floor_collider = std::make_shared(math::fvec3{0.0f, 1.0f, 0.0f}); floor_collider->set_layer_mask(0b11); floor_collider->set_material(std::make_shared(1.0f, 0.5f, 1.0f)); floor_body->set_mass(0.0f); floor_body->set_inertia(0.0f); floor_body->set_collider(std::move(floor_collider)); ctx.entity_registry->emplace(floor_eid, std::move(floor_body)); // Create worker entity(s) auto worker_skeletal_mesh = std::make_unique(worker_model); worker_ant_eid = ctx.entity_registry->create(); transform_component worker_transform_component; worker_transform_component.local = math::transform::identity(); worker_transform_component.local.translation = {0, 0.5f, -4}; worker_transform_component.world = worker_transform_component.local; ctx.entity_registry->emplace(worker_ant_eid, worker_transform_component); ctx.entity_registry->emplace(worker_ant_eid, std::move(worker_skeletal_mesh), std::uint8_t{1}); auto worker_collider = std::make_shared(math::fvec3{-1.0f, -1.0f, -1.0f}, math::fvec3{1.0f, 1.0f, 1.0f}); //auto worker_collider = std::make_shared(1.0f); worker_collider->set_material(std::make_shared(0.4f, 0.1f, 0.2f)); auto worker_body = std::make_unique(); worker_body->set_position(worker_transform_component.local.translation); worker_body->set_previous_position(worker_transform_component.local.translation); worker_body->set_mass(0.1f); worker_body->set_inertia(0.05f); worker_body->set_angular_damping(0.5f); worker_body->set_collider(std::move(worker_collider)); //ctx.entity_registry->emplace(worker_ant_eid, std::move(worker_body)); auto cocoon_eid = ctx.entity_registry->create(); ctx.entity_registry->emplace(cocoon_eid, std::make_shared(worker_phenome.pupa->cocoon_model), std::uint8_t{1}); larva_eid = ctx.entity_registry->create(); auto larva_skeletal_mesh = std::make_shared(worker_phenome.larva->model); //auto larva_skeletal_mesh = std::make_shared(ctx.resource_manager->load("snake.mdl")); const auto& larva_skeleton = larva_skeletal_mesh->get_model()->get_skeleton(); auto larva_ik_rig = std::make_shared(*larva_skeletal_mesh); auto no_twist_constraint = std::make_shared(); no_twist_constraint->set_twist_limit(0.0f, 0.0f); //auto euler_constraint = std::make_shared(); //euler_constraint->set_limits({0.0f, -math::radians(90.0f), 0.0f}, {math::radians(90.0f), math::radians(90.0f), 0.0f}); for (std::size_t i = 0; i < larva_skeleton.get_bone_count(); ++i) { larva_ik_rig->set_constraint(static_cast(i), no_twist_constraint); } const auto larva_ik_root_bone_index = *larva_skeleton.get_bone_index("abdomen3"); const auto larva_ik_effector_bone_index = *larva_skeleton.get_bone_index("head"); const auto& larva_head_absolute_transform = larva_skeletal_mesh->get_pose().get_absolute_transform(larva_ik_effector_bone_index); const auto& larva_head_relative_transform = larva_skeletal_mesh->get_pose().get_relative_transform(larva_ik_effector_bone_index); larva_ik_solver = std::make_shared(*larva_ik_rig, larva_ik_root_bone_index, larva_ik_effector_bone_index); larva_ik_solver->set_effector_position(larva_head_relative_transform * math::fvec3{0.0f, 0.0f, -0.0f}); larva_ik_solver->set_goal_center(larva_head_absolute_transform.translation + math::fvec3{0.2f, 0.2f, 0.5f}); larva_ik_rig->add_solver(larva_ik_solver); //larva_skeletal_mesh->get_pose().set_relative_rotation(larva_ik_root_bone_index, math::angle_axis(math::radians(45.0f), math::fvec3{1.0f, 0.0f, 0.0f})); //larva_skeletal_mesh->get_pose().update(); ctx.entity_registry->emplace(larva_eid, std::move(larva_skeletal_mesh), std::uint8_t{1}); ctx.entity_registry->emplace(larva_eid, std::move(larva_ik_rig)); // Set world time ::world::set_time(ctx, 2022, 6, 21, 12, 0, 0.0); // Init time scale double time_scale = 60.0; // Set time scale ::world::set_time_scale(ctx, time_scale); // Setup and enable sky and ground passes ctx.sky_pass->set_enabled(true); // Set camera exposure const float ev100_sunny16 = physics::light::ev::from_settings(16.0f, 1.0f / 100.0f, 100.0f); ctx.surface_camera->set_exposure_value(ev100_sunny16); const auto& viewport_size = ctx.window->get_viewport_size(); const float aspect_ratio = static_cast(viewport_size[0]) / static_cast(viewport_size[1]); // Init first person camera rig parameters first_person_camera_rig_translation_spring_angular_frequency = physics::s_to_rads(0.125f); first_person_camera_rig_rotation_spring_angular_frequency = physics::s_to_rads(0.125f); first_person_camera_rig_fov_spring_angular_frequency = physics::s_to_rads(0.125f); first_person_camera_rig_min_elevation = 0.25f; first_person_camera_rig_max_elevation = 150.0f; first_person_camera_near_fov = math::vertical_fov(math::radians(100.0f), aspect_ratio); first_person_camera_far_fov = math::vertical_fov(math::radians(60.0f), aspect_ratio); first_person_camera_near_speed = 5.0f; first_person_camera_far_speed = 140.0f; first_person_camera_rig_pedestal_speed = 2.0f; first_person_camera_rig_pedestal = 0.0f; // Create first person camera rig create_first_person_camera_rig(); // Satisfy first person camera rig constraints satisfy_first_person_camera_rig_constraints(); // Setup controls setup_controls(); auto color_checker_archetype = ctx.resource_manager->load("color-checker.ent"); color_checker_archetype->create(*ctx.entity_registry); // auto ruler_archetype = ctx.resource_manager->load("ruler-10cm.ent"); // ruler_archetype->create(*ctx.entity_registry); auto yucca_archetype = ctx.resource_manager->load("yucca-plant-l.ent"); auto yucca_eid = yucca_archetype->create(*ctx.entity_registry); ::command::warp_to(*ctx.entity_registry, yucca_eid, {0, 0, 70}); yucca_archetype = ctx.resource_manager->load("yucca-plant-m.ent"); yucca_eid = yucca_archetype->create(*ctx.entity_registry); ::command::warp_to(*ctx.entity_registry, yucca_eid, {400, 0, 200}); yucca_archetype = ctx.resource_manager->load("yucca-plant-s.ent"); yucca_eid = yucca_archetype->create(*ctx.entity_registry); ::command::warp_to(*ctx.entity_registry, yucca_eid, {-300, 0, -300}); auto cactus_plant_archetype = ctx.resource_manager->load("barrel-cactus-plant-l.ent"); auto cactus_plant_eid = cactus_plant_archetype->create(*ctx.entity_registry); ::command::warp_to(*ctx.entity_registry, cactus_plant_eid, {-100, 0, -200}); cactus_plant_archetype = ctx.resource_manager->load("barrel-cactus-plant-m.ent"); cactus_plant_eid = cactus_plant_archetype->create(*ctx.entity_registry); ::command::warp_to(*ctx.entity_registry, cactus_plant_eid, {100, 0, -70}); cactus_plant_archetype = ctx.resource_manager->load("barrel-cactus-plant-s.ent"); cactus_plant_eid = cactus_plant_archetype->create(*ctx.entity_registry); ::command::warp_to(*ctx.entity_registry, cactus_plant_eid, {50, 0, 80}); // auto cactus_seed_archetype = ctx.resource_manager->load("barrel-cactus-seed.ent"); // auto cactus_seed_eid = cactus_seed_archetype->create(*ctx.entity_registry); // ::command::warp_to(*ctx.entity_registry, cactus_seed_eid, {0, 1, -5}); // Create spring /* auto spring_eid = ctx.entity_registry->create(); auto spring = std::make_unique(); spring->attach_a(); spring->attach_b(); spring->set_resting_length(10.0f); spring->set_stiffness(2.0f); spring->set_damping(1.0f); ctx.entity_registry->emplace(spring_eid, std::move(spring)); */ sky_probe = std::make_shared(); const std::uint32_t sky_probe_face_size = 128; const auto sky_probe_mip_levels = static_cast(std::bit_width(sky_probe_face_size)); sky_probe->set_luminance_texture ( std::make_shared ( std::make_shared ( std::make_shared ( gl::format::r16g16b16_sfloat, sky_probe_face_size, sky_probe_mip_levels ), gl::format::undefined, 0, sky_probe_mip_levels ), std::make_shared ( gl::sampler_filter::linear, gl::sampler_filter::linear, gl::sampler_mipmap_mode::linear, gl::sampler_address_mode::clamp_to_edge, gl::sampler_address_mode::clamp_to_edge ) ) ); ctx.sky_pass->set_sky_probe(sky_probe); ctx.surface_scene->add_object(*sky_probe); // Create sphere auto sphere_eid = ctx.entity_registry->create(); auto sphere_static_mesh = std::make_shared(ctx.resource_manager->load("diffuse-spheres.mdl")); ctx.entity_registry->emplace(sphere_eid, std::move(sphere_static_mesh), std::uint8_t{1}); ctx.entity_registry->patch ( sphere_eid, [&](auto& component) { component.object->set_translation({0.0f, 10.0f, 0.0f}); } ); // Queue enable game controls ctx.function_queue.push ( [&ctx]() { ::enable_game_controls(ctx); } ); // Queue fade in ctx.fade_transition_color->set({0, 0, 0}); ctx.function_queue.push(std::bind(&screen_transition::transition, ctx.fade_transition.get(), 1.0f, true, ease::out_sine, true, nullptr)); // Refresh frame scheduler ctx.frame_scheduler.refresh(); debug::log_trace("Entered nest selection state"); } nest_selection_state::~nest_selection_state() { debug::log_trace("Exiting nest selection state..."); // Disable game controls ::disable_game_controls(ctx); destroy_first_person_camera_rig(); debug::log_trace("Exited nest selection state"); } void nest_selection_state::create_first_person_camera_rig() { // Construct first person camera rig transform component transform_component first_person_camera_rig_transform; first_person_camera_rig_transform.local = math::transform::identity(); first_person_camera_rig_transform.local.translation = {0, 10, 0}; first_person_camera_rig_transform.world = first_person_camera_rig_transform.local; // Construct first person camera rig locomotion component winged_locomotion_component first_person_camera_rig_locomotion; // Construct first person camera rig physics component auto first_person_camera_rig_body = std::make_unique(); first_person_camera_rig_body->set_position({0, 10, 0}); first_person_camera_rig_body->set_mass(1.0f); first_person_camera_rig_body->set_linear_damping(10.0f); first_person_camera_rig_body->set_angular_damping(0.5f); auto first_person_camera_rig_collider = std::make_shared(1.0f); auto camera_collider_material = std::make_shared(0.0f, 0.0f, 0.0f); camera_collider_material->set_restitution_combine_mode(physics::restitution_combine_mode::minimum); camera_collider_material->set_friction_combine_mode(physics::friction_combine_mode::minimum); first_person_camera_rig_collider->set_layer_mask(0b10); first_person_camera_rig_collider->set_material(std::move(camera_collider_material)); first_person_camera_rig_body->set_collider(std::move(first_person_camera_rig_collider)); // Construct first person camera rig scene component scene_component first_person_camera_rig_camera; first_person_camera_rig_camera.object = ctx.surface_camera; // Construct first person camera rig entity first_person_camera_rig_eid = ctx.entity_registry->create(); ctx.entity_registry->emplace(first_person_camera_rig_eid, first_person_camera_rig_camera); ctx.entity_registry->emplace(first_person_camera_rig_eid, first_person_camera_rig_transform); ctx.entity_registry->emplace(first_person_camera_rig_eid, std::move(first_person_camera_rig_body)); ctx.entity_registry->emplace(first_person_camera_rig_eid, first_person_camera_rig_locomotion); } void nest_selection_state::destroy_first_person_camera_rig() { ctx.entity_registry->destroy(first_person_camera_rig_eid); } void nest_selection_state::set_first_person_camera_rig_pedestal(float pedestal) { } void nest_selection_state::move_first_person_camera_rig(const math::fvec2& direction, float factor) { } void nest_selection_state::satisfy_first_person_camera_rig_constraints() { } void nest_selection_state::setup_controls() { constexpr float movement_speed = 200.0f; auto move_first_person_camera_rig = [&](const math::fvec2& direction, float speed) { const transform_component& first_person_camera_rig_transform = ctx.entity_registry->get(first_person_camera_rig_eid); const math::fquat yaw_rotation = math::angle_axis(static_cast(first_person_camera_yaw), math::fvec3{0.0f, 1.0f, 0.0f}); const math::fvec3 rotated_direction = yaw_rotation * math::fvec3{direction[0], 0.0f, direction[1]}; const math::fvec3 force = rotated_direction * speed; moving = true; movement_direction = direction; this->movement_speed = speed; ctx.entity_registry->patch ( first_person_camera_rig_eid, [&](auto& component) { component.force = force; } ); }; auto stop_first_person_camera_rig = [&]() { moving = false; ctx.entity_registry->patch ( first_person_camera_rig_eid, [&](auto& component) { component.force = {0.0f, 0.0f, 0.0f}; } ); }; // Mouse look mouse_motion_subscription = ctx.input_manager->get_event_dispatcher().subscribe ( [&, move_first_person_camera_rig](const auto& event) { if (adjust_time) { const double sensitivity = 1.0 / static_cast(ctx.window->get_viewport_size().x()); const double t = ctx.astronomy_system->get_time(); ::world::set_time(ctx, t + static_cast(event.difference.x()) * sensitivity); /* sky_probe->update_illuminance_matrices(); const auto matrices = sky_probe->get_illuminance_matrices(); for (std::size_t i = 0; i < 3; ++i) { const auto m = matrices[i]; debug::log_warning("\nmat4({},{},{},{},\n{},{},{},{},\n{},{},{},{},\n{},{},{},{});", m[0][0], m[0][1], m[0][2], m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3], m[3][0], m[3][1], m[3][2], m[3][3]); } */ } if (adjust_exposure) { const float sensitivity = 8.0f / static_cast(ctx.window->get_viewport_size().y()); ctx.surface_camera->set_exposure_value(ctx.surface_camera->get_exposure_value() + static_cast(event.difference.y()) * sensitivity); } if (!mouse_look) { return; } first_person_camera_yaw -= ctx.mouse_pan_factor * static_cast(event.difference.x()); first_person_camera_pitch += ctx.mouse_tilt_factor * static_cast(event.difference.y()); first_person_camera_pitch = std::min(math::half_pi, std::max(-math::half_pi, first_person_camera_pitch)); const math::dquat yaw_rotation = math::angle_axis(first_person_camera_yaw, {0.0f, 1.0, 0.0}); const math::dquat pitch_rotation = math::angle_axis(first_person_camera_pitch, {-1.0, 0.0, 0.0}); const math::fquat first_person_camera_orientation = math::fquat(math::normalize(yaw_rotation * pitch_rotation)); ctx.entity_registry->patch ( first_person_camera_rig_eid, [&](auto& component) { component.object->set_rotation(first_person_camera_orientation); } ); ctx.entity_registry->patch ( first_person_camera_rig_eid, [&](auto& component) { component.body->set_previous_orientation(first_person_camera_orientation); component.body->set_orientation(first_person_camera_orientation); } ); ctx.entity_registry->patch ( first_person_camera_rig_eid, [&](auto& component) { component.local.rotation = first_person_camera_orientation; component.world.rotation = first_person_camera_orientation; } ); if (moving) { move_first_person_camera_rig(movement_direction, this->movement_speed); } } ); // Move forward action_subscriptions.emplace_back ( ctx.move_forward_action.get_active_channel().subscribe ( [&, move_first_person_camera_rig](const auto& event) { move_first_person_camera_rig({0.0f, -1.0f}, movement_speed * event.input_value); } ) ); action_subscriptions.emplace_back ( ctx.move_forward_action.get_deactivated_channel().subscribe ( [&, stop_first_person_camera_rig](const auto& event) { stop_first_person_camera_rig(); } ) ); // Move back action_subscriptions.emplace_back ( ctx.move_back_action.get_active_channel().subscribe ( [&, move_first_person_camera_rig](const auto& event) { move_first_person_camera_rig({0, 1}, movement_speed * event.input_value); } ) ); action_subscriptions.emplace_back ( ctx.move_back_action.get_deactivated_channel().subscribe ( [&, stop_first_person_camera_rig](const auto& event) { stop_first_person_camera_rig(); } ) ); // Move left action_subscriptions.emplace_back ( ctx.move_left_action.get_active_channel().subscribe ( [&, move_first_person_camera_rig](const auto& event) { move_first_person_camera_rig({-1, 0}, movement_speed * event.input_value); } ) ); action_subscriptions.emplace_back ( ctx.move_left_action.get_deactivated_channel().subscribe ( [&, stop_first_person_camera_rig](const auto& event) { stop_first_person_camera_rig(); } ) ); // Move right action_subscriptions.emplace_back ( ctx.move_right_action.get_active_channel().subscribe ( [&, move_first_person_camera_rig](const auto& event) { move_first_person_camera_rig({1, 0}, movement_speed * event.input_value); } ) ); action_subscriptions.emplace_back ( ctx.move_right_action.get_deactivated_channel().subscribe ( [&, stop_first_person_camera_rig](const auto& event) { stop_first_person_camera_rig(); } ) ); // Move up action_subscriptions.emplace_back ( ctx.move_up_action.get_activated_channel().subscribe ( [&](const auto& event) { ctx.entity_registry->patch ( first_person_camera_rig_eid, [&](auto& component) { component.body->apply_central_impulse({0, 5.0f, 0}); } ); } ) ); // Move down action_subscriptions.emplace_back ( ctx.move_down_action.get_activated_channel().subscribe ( [&](const auto& event) { ctx.entity_registry->patch ( first_person_camera_rig_eid, [&](auto& component) { component.body->apply_central_impulse({0, -5.0f, 0}); } ); } ) ); /* // Focus action_subscriptions.emplace_back ( ctx.focus_action.get_activated_channel().subscribe ( [&](const auto& event) { auto projectile_eid = ctx.entity_registry->create(); const auto& camera_transform = ctx.entity_registry->get(first_person_camera_rig_eid); scene_component projectile_scene; transform_component projectile_transform; projectile_transform.local = camera_transform.world; projectile_transform.world = projectile_transform.local; auto projectile_body = std::make_unique(); projectile_body->set_position(camera_transform.world.translation); projectile_body->set_previous_position(camera_transform.world.translation); projectile_body->set_mass(0.1f); projectile_body->set_inertia(0.05f); projectile_body->set_angular_damping(0.5f); if (ctx.mouse_look_action.is_active()) { auto projectile_collider = std::make_shared(1.0f); //auto projectile_collider = std::make_shared(math::fvec3{-1.0f, -1.0f, -1.0f}, math::fvec3{1.0f, 1.0f, 1.0f}); projectile_collider->set_material(std::make_shared(0.4f, 0.1f, 0.2f)); projectile_body->set_collider(std::move(projectile_collider)); projectile_scene.object = std::make_shared(ctx.resource_manager->load("sphere.mdl")); //projectile_scene.object = std::make_shared(ctx.resource_manager->load("cube.mdl")); } else { auto projectile_collider = std::make_shared(geom::capsule{{{0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, -1.0f}}, 0.6f}); projectile_collider->set_material(std::make_shared(0.4f, 0.1f, 0.2f)); projectile_body->set_collider(std::move(projectile_collider)); //projectile_scene.object = std::make_shared(ctx.resource_manager->load("capsule.mdl")); auto projectile_mesh = std::make_shared(worker_model); projectile_mesh->get_pose() = *worker_model->get_skeleton().get_pose("pupa"); projectile_scene.object = projectile_mesh; } projectile_body->apply_central_impulse(camera_transform.world.rotation * math::fvec3{0.0f, 0.0f, -10.0f}); // auto spring_eid = ctx.entity_registry->create(); // auto spring = std::make_unique(); // spring->attach_a(*ctx.entity_registry->get(first_person_camera_rig_eid).body, {0.0f, 0.0f, 0.0f}); // spring->attach_b(*projectile_body, {0.0f, 0.0f, 0.0f}); // spring->set_resting_length(10.0f); // spring->set_stiffness(2.0f); // spring->set_damping(1.0f); // ctx.entity_registry->emplace(spring_eid, std::move(spring)); ctx.entity_registry->emplace(projectile_eid, projectile_transform); ctx.entity_registry->emplace(projectile_eid, std::move(projectile_scene)); ctx.entity_registry->emplace(projectile_eid, std::move(projectile_body)); // body.linear_momentum = math::fvec3::zero(); // body.angular_momentum = math::fvec3::zero(); // body.linear_velocity = math::fvec3::zero(); // body.angular_velocity = math::fvec3::zero(); //body.apply_central_impulse({0.0f, 100.5f, 0.0f}); // ctx.entity_registry->patch // ( // first_person_camera_rig_track_to_eid, // [&](auto& component) // { // component.active = true; // } // ); } ) ); action_subscriptions.emplace_back ( ctx.focus_action.get_deactivated_channel().subscribe ( [&](const auto& event) { } ) ); */ } void nest_selection_state::enable_controls() { } void nest_selection_state::disable_controls() { }