use super::{ControlState, ControllerSet}; use crate::{GameState, control::controller_common::MovementSpeedFactor, player::PlayerBodyMesh}; use bevy::prelude::*; use happy_feet::prelude::MoveInput; use std::f32::consts::PI; pub struct CharacterControllerPlugin; impl Plugin for CharacterControllerPlugin { fn build(&self, app: &mut App) { app.add_systems( PreUpdate, (rotate_rig, apply_controls) .chain() .in_set(ControllerSet::ApplyControlsFly) .run_if(in_state(GameState::Playing)), ); } } fn rotate_rig( mut rig_transform_q: Option>>, controls: Res, ) { if controls.view_mode { return; } let look_dir = controls.look_dir; if let Some(ref mut rig_transform) = rig_transform_q { // todo: Make consistent with the running controller let sensitivity = 0.001; let max_pitch = 35.0 * PI / 180.0; let min_pitch = -25.0 * PI / 180.0; rig_transform.rotate_y(look_dir.x * -sensitivity); let euler_rot = rig_transform.rotation.to_euler(EulerRot::YXZ); let yaw = euler_rot.0; let pitch = euler_rot.1 + look_dir.y * sensitivity; let pitch_clamped = pitch.clamp(min_pitch, max_pitch); rig_transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch_clamped, 0.0); // The following can be used to limit the amount of rotation per frame // let target_rotation = rig_transform.rotation // * Quat::from_rotation_x(controls.keyboard_state.look_dir.y * sensitivity); // let clamped_rotation = rig_transform.rotation.rotate_towards(target_rotation, 0.01); // rig_transform.rotation = clamped_rotation; } } fn apply_controls( mut character: Query<(&mut MoveInput, &MovementSpeedFactor)>, rig_transform_q: Option>>, ) { let (mut char_input, factor) = character.single_mut().unwrap(); if let Some(ref rig_transform) = rig_transform_q { char_input.set(-*rig_transform.forward() * factor.0); } }