remove damping

* try fix sliding upwards gaining speed
This commit is contained in:
2025-03-27 00:00:11 +08:00
parent ad6e4a1272
commit 7fa31a91a6
3 changed files with 44 additions and 117 deletions

View File

@@ -99,6 +99,7 @@ pub fn kinematic_controller_collisions(
// up and down the surface smoothly. // up and down the surface smoothly.
if climbable { if climbable {
// Points in the normal's direction in the XZ plane. // Points in the normal's direction in the XZ plane.
let normal_direction_xz = let normal_direction_xz =
normal.reject_from_normalized(Vector::Y).normalize_or_zero(); normal.reject_from_normalized(Vector::Y).normalize_or_zero();
@@ -120,7 +121,11 @@ pub fn kinematic_controller_collisions(
// *───────────────────* // *───────────────────*
let max_y_speed = -linear_velocity_xz * slope_angle.tan(); let max_y_speed = -linear_velocity_xz * slope_angle.tan();
linear_velocity.y = linear_velocity.y.max(max_y_speed);
// TODO: figure out why this is needed, without it we
// cannot do these crate to crate jumps anymore which is intented.
// linear_velocity.y = linear_velocity.y.max(max_y_speed);
} else { } else {
// The character is intersecting an unclimbable object, like a wall. // The character is intersecting an unclimbable object, like a wall.
// We want the character to slide along the surface, similarly to // We want the character to slide along the surface, similarly to

View File

@@ -1,32 +1,21 @@
use super::{ControllerSet, Controls, collisions::kinematic_controller_collisions};
use crate::{GameState, player::PlayerRig};
use avian3d::{math::*, prelude::*}; use avian3d::{math::*, prelude::*};
use bevy::{ecs::query::Has, prelude::*}; use bevy::{ecs::query::Has, prelude::*};
use crate::{GameState, player::PlayerRig};
use super::{ControllerSet, Controls, collisions::kinematic_controller_collisions};
pub struct CharacterControllerPlugin; pub struct CharacterControllerPlugin;
impl Plugin for CharacterControllerPlugin { impl Plugin for CharacterControllerPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.init_resource::<PlayerMovement>(); app.init_resource::<PlayerMovement>();
app.init_resource::<MovementSettings>();
app.register_type::<MovementSettings>();
app.register_type::<MovementDampingFactor>();
app.register_type::<JumpImpulse>(); app.register_type::<JumpImpulse>();
app.register_type::<ControllerGravity>(); app.register_type::<ControllerGravity>();
app.register_type::<MovementAcceleration>(); app.register_type::<MovementAcceleration>();
app.add_systems( app.add_systems(
Update, Update,
( (set_movement_flag, update_grounded, apply_gravity, movement)
set_movement_flag,
brake_on_release,
update_grounded,
apply_gravity,
movement,
apply_movement_damping,
)
.chain() .chain()
.in_set(ControllerSet::ApplyControls) .in_set(ControllerSet::ApplyControls)
.run_if(in_state(GameState::Playing)), .run_if(in_state(GameState::Playing)),
@@ -56,35 +45,11 @@ pub struct PlayerMovement {
pub any_direction: bool, pub any_direction: bool,
} }
#[derive(Resource, Reflect)]
#[reflect(Resource)]
struct MovementSettings {
damping_normal: f32,
damping_brake: f32,
damping_brake_air: f32,
}
// todo some duplicate with player.rs settings
impl Default for MovementSettings {
fn default() -> Self {
Self {
damping_normal: 1.0,
damping_brake: 30.0,
damping_brake_air: 1.0,
}
}
}
/// The acceleration used for character movement. /// The acceleration used for character movement.
#[derive(Component, Reflect)] #[derive(Component, Reflect)]
#[reflect(Component)] #[reflect(Component)]
pub struct MovementAcceleration(Scalar); pub struct MovementAcceleration(Scalar);
/// The damping factor used for slowing down movement.
#[derive(Component, Reflect)]
#[reflect(Component)]
pub struct MovementDampingFactor(Scalar);
/// The strength of a jump. /// The strength of a jump.
#[derive(Component, Reflect)] #[derive(Component, Reflect)]
#[reflect(Component)] #[reflect(Component)]
@@ -118,35 +83,22 @@ pub struct CharacterControllerBundle {
#[derive(Bundle)] #[derive(Bundle)]
pub struct MovementBundle { pub struct MovementBundle {
acceleration: MovementAcceleration, acceleration: MovementAcceleration,
damping: MovementDampingFactor,
jump_impulse: JumpImpulse, jump_impulse: JumpImpulse,
max_slope_angle: MaxSlopeAngle, max_slope_angle: MaxSlopeAngle,
} }
impl MovementBundle { impl MovementBundle {
pub const fn new( pub const fn new(acceleration: Scalar, jump_impulse: Scalar, max_slope_angle: Scalar) -> Self {
acceleration: Scalar,
damping: Scalar,
jump_impulse: Scalar,
max_slope_angle: Scalar,
) -> Self {
Self { Self {
acceleration: MovementAcceleration(acceleration), acceleration: MovementAcceleration(acceleration),
damping: MovementDampingFactor(damping),
jump_impulse: JumpImpulse(jump_impulse), jump_impulse: JumpImpulse(jump_impulse),
max_slope_angle: MaxSlopeAngle(max_slope_angle), max_slope_angle: MaxSlopeAngle(max_slope_angle),
} }
} }
} }
impl Default for MovementBundle {
fn default() -> Self {
Self::new(30.0, 0.9, 7.0, PI * 0.45)
}
}
impl CharacterControllerBundle { impl CharacterControllerBundle {
pub fn new(collider: Collider, gravity: Vector) -> Self { pub fn new(collider: Collider, gravity: Vector, movement: MovementBundle) -> Self {
// Create shape caster as a slightly smaller version of collider // Create shape caster as a slightly smaller version of collider
let mut caster_shape = collider.clone(); let mut caster_shape = collider.clone();
caster_shape.set_scale(Vector::ONE * 0.98, 10); caster_shape.set_scale(Vector::ONE * 0.98, 10);
@@ -163,39 +115,7 @@ impl CharacterControllerBundle {
) )
.with_max_distance(0.2), .with_max_distance(0.2),
gravity: ControllerGravity(gravity), gravity: ControllerGravity(gravity),
movement: MovementBundle::default(), movement,
}
}
pub fn with_movement(
mut self,
acceleration: Scalar,
damping: Scalar,
jump_impulse: Scalar,
max_slope_angle: Scalar,
) -> Self {
self.movement = MovementBundle::new(acceleration, damping, jump_impulse, max_slope_angle);
self
}
}
/// Apply extra friction when no movement input is given
/// In the original you stop instantly in this case
fn brake_on_release(
player_movement: Res<PlayerMovement>,
movement_settings: Res<MovementSettings>,
mut damping_q: Query<(Entity, &mut MovementDampingFactor)>,
grounded_q: Query<&Grounded>,
) {
for (entity, mut damping) in &mut damping_q {
let is_grounded = grounded_q.get(entity).is_ok();
if !player_movement.any_direction && is_grounded {
damping.0 = movement_settings.damping_brake;
} else if !player_movement.any_direction && !is_grounded {
damping.0 = movement_settings.damping_brake_air;
} else {
damping.0 = movement_settings.damping_normal;
} }
} }
} }
@@ -220,8 +140,10 @@ fn update_grounded(
}); });
if is_grounded { if is_grounded {
info!("grounded");
commands.entity(entity).insert(Grounded); commands.entity(entity).insert(Grounded);
} else { } else {
info!("not grounded");
commands.entity(entity).remove::<Grounded>(); commands.entity(entity).remove::<Grounded>();
} }
} }
@@ -256,19 +178,22 @@ fn movement(
Has<Grounded>, Has<Grounded>,
)>, )>,
rig_transform_q: Option<Single<&GlobalTransform, With<PlayerRig>>>, rig_transform_q: Option<Single<&GlobalTransform, With<PlayerRig>>>,
mut jump_used: Local<bool>,
) { ) {
let delta_time = time.delta_secs(); let delta_time = time.delta_secs();
let mut direction = controls.keyboard_state.move_dir; let mut direction = controls.keyboard_state.move_dir;
let mut jump_requested = controls.keyboard_state.jump; let mut jump_requested = controls.keyboard_state.jump;
if let Some(gamepad) = controls.gamepad_state { if let Some(gamepad) = controls.gamepad_state {
direction += gamepad.move_dir; direction += gamepad.move_dir;
direction = direction.normalize_or_zero();
jump_requested |= gamepad.jump; jump_requested |= gamepad.jump;
} }
direction = direction.normalize_or_zero();
for (movement_acceleration, jump_impulse, mut linear_velocity, is_grounded) in &mut controllers for (movement_acceleration, jump_impulse, mut linear_velocity, is_grounded) in &mut controllers
{ {
let mut direction = direction.extend(0.0).xzy(); let mut direction = direction.extend(0.0).xzy();
@@ -278,11 +203,22 @@ fn movement(
(rig_transform.forward() * direction.z) + (rig_transform.right() * direction.x); (rig_transform.forward() * direction.z) + (rig_transform.right() * direction.x);
} }
linear_velocity.x -= direction.x * movement_acceleration.0 * delta_time; linear_velocity.x = -direction.x * movement_acceleration.0 * delta_time;
linear_velocity.z -= direction.z * movement_acceleration.0 * delta_time; linear_velocity.z = -direction.z * movement_acceleration.0 * delta_time;
if is_grounded && jump_requested { if is_grounded && jump_requested && !*jump_used {
linear_velocity.y = jump_impulse.0; linear_velocity.y = jump_impulse.0;
info!("jump");
*jump_used = true;
}
if !controls.keyboard_state.jump
&& !controls
.gamepad_state
.map(|state| state.jump)
.unwrap_or_default()
{
*jump_used = false;
} }
} }
} }
@@ -290,25 +226,13 @@ fn movement(
/// Applies [`ControllerGravity`] to character controllers. /// Applies [`ControllerGravity`] to character controllers.
fn apply_gravity( fn apply_gravity(
time: Res<Time>, time: Res<Time>,
mut controllers: Query<(&ControllerGravity, &mut LinearVelocity)>, mut controllers: Query<(&ControllerGravity, &mut LinearVelocity, Option<&Grounded>)>,
) { ) {
let delta_time = time.delta_secs(); let delta_time = time.delta_secs();
for (gravity, mut linear_velocity) in &mut controllers { for (gravity, mut linear_velocity, grounded) in &mut controllers {
if grounded.is_none() {
linear_velocity.0 += gravity.0 * delta_time; linear_velocity.0 += gravity.0 * delta_time;
} }
} }
/// Slows down movement in the XZ plane.
fn apply_movement_damping(
time: Res<Time>,
mut query: Query<(&MovementDampingFactor, &mut LinearVelocity)>,
) {
let delta_time = time.delta_secs();
for (damping_factor, mut linear_velocity) in &mut query {
// We could use `LinearDamping`, but we don't want to dampen movement along the Y axis
linear_velocity.x *= 1.0 - damping_factor.0 * delta_time;
linear_velocity.z *= 1.0 - damping_factor.0 * delta_time;
}
} }

View File

@@ -5,7 +5,7 @@ use crate::{
cash::{Cash, CashCollectEvent}, cash::{Cash, CashCollectEvent},
control::{ control::{
Controls, Controls,
controller::{CharacterControllerBundle, PlayerMovement}, controller::{CharacterControllerBundle, MovementBundle, PlayerMovement},
}, },
heads_ui::HeadChanged, heads_ui::HeadChanged,
loading_assets::GameAssets, loading_assets::GameAssets,
@@ -87,8 +87,7 @@ fn spawn(
let gravity = Vector::NEG_Y * 40.0; let gravity = Vector::NEG_Y * 40.0;
let collider = Collider::capsule(0.9, 1.2); let collider = Collider::capsule(0.9, 1.2);
let acceleration = 30.0; let acceleration = 30.0 * 60.;
let damping = 0.95;
let jump_impulse = 18.0; let jump_impulse = 18.0;
let max_slope_angle = (60.0 as Scalar).to_radians(); let max_slope_angle = (60.0 as Scalar).to_radians();
@@ -101,11 +100,10 @@ fn spawn(
Visibility::default(), Visibility::default(),
// LockedAxes::ROTATION_LOCKED, todo // LockedAxes::ROTATION_LOCKED, todo
CollisionLayers::new(LayerMask(GameLayer::Player.to_bits()), LayerMask::ALL), CollisionLayers::new(LayerMask(GameLayer::Player.to_bits()), LayerMask::ALL),
CharacterControllerBundle::new(collider, gravity).with_movement( CharacterControllerBundle::new(
acceleration, collider,
damping, gravity,
jump_impulse, MovementBundle::new(acceleration, jump_impulse, max_slope_angle),
max_slope_angle,
), ),
)) ))
.with_children(|parent| { .with_children(|parent| {