Player drag and alignment with gravity

+player jumping
This commit is contained in:
2025-06-25 15:55:25 -04:00
parent 8c3281f9cc
commit 11d6c52791
6 changed files with 118 additions and 24 deletions

View File

@@ -1,9 +1,14 @@
use std::f32::EPSILON;
use bevy::prelude::*;
use bevy_rapier3d::prelude::*;
use crate::components::{
player::{GravityDirection, PlayerForce, PlayerMotion, PlayerVelocity},
tags::Player,
use crate::{
components::{
player::{GravityDirection, JumpSpeed, MoveSpeed, PlayerDrag, PlayerForce, PlayerMotion, PlayerVelocity},
tags::Player,
},
utils::rotation::get_alignment_rotation,
};
pub struct PlayerPlugin;
@@ -11,15 +16,16 @@ pub struct PlayerPlugin;
impl Plugin for PlayerPlugin {
fn build(&self, app: &mut App) {
app.add_systems(PreUpdate, keyboard_input.in_set(PlayerInputSystems));
app.add_systems(Update, (apply_gravity, apply_forces, apply_motion).chain());
app.add_systems(Update, (apply_gravity, apply_forces, apply_motion, apply_drag).chain());
app.add_systems(Update, align_with_gravity);
}
}
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
pub struct PlayerInputSystems;
fn apply_forces(player: Single<(&mut PlayerVelocity, &mut PlayerForce), With<Player>>, time: Res<Time>) {
let (mut vel, mut force) = player.into_inner();
fn apply_forces(player: Single<(&mut PlayerVelocity, &PlayerForce), With<Player>>, time: Res<Time>) {
let (mut vel, force) = player.into_inner();
vel.0 += force.0 * time.delta_secs();
}
@@ -44,10 +50,18 @@ fn apply_gravity(
if !is_grounded {
vel.0 += grav * scale.0 * 9.47 * time.delta_secs();
} else {
vel.0 = vel.0 - vel.0.dot(grav) * grav;
let dot = vel.0.dot(grav);
if dot > 0.0 {
vel.0 = vel.0 - dot * grav;
}
}
}
fn apply_drag(player: Single<(&mut PlayerVelocity, &PlayerDrag), With<Player>>, time: Res<Time>) {
let (mut vel, drag) = player.into_inner();
vel.0 *= (1.0 - drag.0 * time.delta_secs()).max(0.0);
}
fn apply_motion(
player: Single<
(
@@ -61,10 +75,9 @@ fn apply_motion(
time: Res<Time>,
) {
let (mut controller, transform, vel, motion) = player.into_inner();
let max_vel = vel.0.clamp_length_max(500.0);
// let max_vel = vel.0.clamp_length_max(500.0);
let global_motion = transform.rotation * motion.0;
controller.translation =
Some((max_vel + global_motion) * controller.custom_mass.unwrap_or(1.0) * time.delta_secs());
controller.translation = Some((vel.0 + global_motion) * controller.custom_mass.unwrap_or(1.0) * time.delta_secs());
}
fn keyboard_input(
@@ -73,13 +86,15 @@ fn keyboard_input(
(
&mut PlayerMotion,
&mut PlayerVelocity,
&MoveSpeed,
&JumpSpeed,
&Transform,
Option<&KinematicCharacterControllerOutput>,
),
With<Player>,
>,
) {
let (mut motion, mut vel, transform, output) = player.into_inner();
let (mut motion, mut vel, speed, jump, transform, output) = player.into_inner();
let mut move_vec = Vec3::ZERO;
if key.pressed(KeyCode::KeyW) {
@@ -94,18 +109,13 @@ fn keyboard_input(
move_vec.x = 1.0;
}
move_vec = move_vec.normalize_or_zero() * speed.0;
let is_grounded = output.map(|o| o.grounded).unwrap_or(false);
if key.just_pressed(KeyCode::Space) && is_grounded {
vel.0 += transform.up() * 200.0;
vel.0 += transform.up() * jump.0;
}
let angle = if key.pressed(KeyCode::KeyQ) {
-0.1
} else if key.pressed(KeyCode::KeyE) {
0.1
} else {
0.0
};
motion.0 = move_vec;
// transform.rotate_z(angle * time.delta_secs());
@@ -113,3 +123,32 @@ fn keyboard_input(
// move_vec += transform.down().as_vec3();
// controller.translation = Some(move_vec * time.delta_secs());
}
fn align_with_gravity(
player: Single<
(
&mut Transform,
&GravityDirection,
Option<&KinematicCharacterControllerOutput>,
),
With<Player>,
>,
time: Res<Time>,
) {
let (mut transform, grav, output) = player.into_inner();
let is_grounded = output.map(|o| o.grounded).unwrap_or(false);
if !is_grounded {
return;
}
let Some(grav_dir) = grav.0 else {
return;
};
let cur_up = transform.up();
let grav_up = grav_dir * -1.0;
let desired_rotation = get_alignment_rotation(cur_up, grav_up);
transform.rotation = transform.rotation.lerp(desired_rotation, time.delta_secs());
}