use super::{ControlState, ControllerSet, Controls}; use crate::control::controller_common::MovementSpeedFactor; use crate::control::controls::ControllerSettings; use crate::{GameState, abilities::TriggerStateRes, player::PlayerBodyMesh}; use bevy::prelude::*; use happy_feet::prelude::{Grounding, KinematicVelocity, MoveInput}; use super::controller_common::PlayerMovement; pub struct CharacterControllerPlugin; impl Plugin for CharacterControllerPlugin { fn build(&self, app: &mut App) { app.add_systems( PreUpdate, (set_movement_flag, rotate_view, apply_controls) .chain() .in_set(ControllerSet::ApplyControlsRun) .run_if(in_state(GameState::Playing)), ); } } /// Sets the movement flag, which is an indicator for the rig animation and the braking system. fn set_movement_flag( mut player_movement: ResMut, controls: Res, trigger: Res, ) { let mut direction = controls.keyboard_state.move_dir; let deadzone = 0.2; if let Some(gamepad) = controls.gamepad_state { direction += gamepad.move_dir; } if player_movement.any_direction { if direction.length_squared() < deadzone { player_movement.any_direction = false; } } else if direction.length_squared() > deadzone { player_movement.any_direction = true; } if player_movement.shooting != trigger.is_active() { player_movement.shooting = trigger.is_active(); } } fn rotate_view( controls: Res, mut player: Query<&mut Transform, With>, ) { if controls.view_mode { return; } for mut tr in &mut player { tr.rotate_y(controls.look_dir.x * -0.001); } } fn apply_controls( controls: Res, mut character: Query<( &mut MoveInput, &mut Grounding, &mut KinematicVelocity, &ControllerSettings, &MovementSpeedFactor, )>, rig_transform_q: Option>>, ) { let Ok((mut move_input, mut grounding, mut velocity, settings, move_factor)) = character.single_mut() else { return; }; let mut direction = -controls.move_dir.extend(0.0).xzy(); if let Some(ref rig_transform) = rig_transform_q { direction = (rig_transform.forward() * direction.z) + (rig_transform.right() * direction.x); } let ground_normal = *grounding.normal().unwrap_or(Dir3::Y); let y_projection = direction.project_onto(ground_normal); direction -= y_projection; direction = direction.normalize_or_zero(); move_input.set(direction * move_factor.0); if controls.jump && grounding.is_grounded() { happy_feet::movement::jump(settings.jump_force, &mut velocity, &mut grounding, Dir3::Y) } }