use super::{ControlState, ControllerSet}; use crate::{ GameState, animation::AnimationFlags, control::{ControllerSettings, controller_common::MovementSpeedFactor}, }; #[cfg(feature = "client")] use crate::{control::LookDirMovement, player::PlayerBodyMesh}; use bevy::prelude::*; use happy_feet::prelude::{Grounding, KinematicVelocity, MoveInput}; use lightyear::prelude::input::native::ActionState; pub struct CharacterControllerPlugin; impl Plugin for CharacterControllerPlugin { fn build(&self, app: &mut App) { app.add_systems( FixedUpdate, ( #[cfg(feature = "client")] rotate_view, apply_controls, ) .chain() .in_set(ControllerSet::ApplyControlsRun) .run_if(in_state(GameState::Playing)), ); } } #[cfg(feature = "client")] fn rotate_view( actions: Query<&ActionState>, look_dir: Res, mut player: Query<(&mut Transform, &ChildOf), With>, ) { for (mut tr, child_of) in player.iter_mut() { let controls = actions.get(child_of.parent()).unwrap(); if controls.view_mode { continue; } tr.rotate_y(look_dir.0.x * -0.001); } } fn apply_controls( character: Single<( &mut MoveInput, &mut Grounding, &mut KinematicVelocity, &mut AnimationFlags, &ControllerSettings, &MovementSpeedFactor, &ActionState, )>, ) { let (mut move_input, mut grounding, mut velocity, mut flags, settings, move_factor, controls) = character.into_inner(); let ground_normal = *grounding.normal().unwrap_or(Dir3::Y); let mut direction = controls.move_dir.extend(0.0).xzy(); let look_dir_right = controls.look_dir.cross(Vec3::Y); direction = (controls.look_dir * direction.z) + (look_dir_right * direction.x); 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() { if cfg!(feature = "server") { flags.jumping = true; flags.jump_count += 1; } happy_feet::movement::jump(settings.jump_force, &mut velocity, &mut grounding, Dir3::Y) } }