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.
if climbable {
// Points in the normal's direction in the XZ plane.
let normal_direction_xz =
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();
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 {
// The character is intersecting an unclimbable object, like a wall.
// 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 bevy::{ecs::query::Has, prelude::*};
use crate::{GameState, player::PlayerRig};
use super::{ControllerSet, Controls, collisions::kinematic_controller_collisions};
pub struct CharacterControllerPlugin;
impl Plugin for CharacterControllerPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<PlayerMovement>();
app.init_resource::<MovementSettings>();
app.register_type::<MovementSettings>();
app.register_type::<MovementDampingFactor>();
app.register_type::<JumpImpulse>();
app.register_type::<ControllerGravity>();
app.register_type::<MovementAcceleration>();
app.add_systems(
Update,
(
set_movement_flag,
brake_on_release,
update_grounded,
apply_gravity,
movement,
apply_movement_damping,
)
(set_movement_flag, update_grounded, apply_gravity, movement)
.chain()
.in_set(ControllerSet::ApplyControls)
.run_if(in_state(GameState::Playing)),
@@ -56,35 +45,11 @@ pub struct PlayerMovement {
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.
#[derive(Component, Reflect)]
#[reflect(Component)]
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.
#[derive(Component, Reflect)]
#[reflect(Component)]
@@ -118,35 +83,22 @@ pub struct CharacterControllerBundle {
#[derive(Bundle)]
pub struct MovementBundle {
acceleration: MovementAcceleration,
damping: MovementDampingFactor,
jump_impulse: JumpImpulse,
max_slope_angle: MaxSlopeAngle,
}
impl MovementBundle {
pub const fn new(
acceleration: Scalar,
damping: Scalar,
jump_impulse: Scalar,
max_slope_angle: Scalar,
) -> Self {
pub const fn new(acceleration: Scalar, jump_impulse: Scalar, max_slope_angle: Scalar) -> Self {
Self {
acceleration: MovementAcceleration(acceleration),
damping: MovementDampingFactor(damping),
jump_impulse: JumpImpulse(jump_impulse),
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 {
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
let mut caster_shape = collider.clone();
caster_shape.set_scale(Vector::ONE * 0.98, 10);
@@ -163,39 +115,7 @@ impl CharacterControllerBundle {
)
.with_max_distance(0.2),
gravity: ControllerGravity(gravity),
movement: MovementBundle::default(),
}
}
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;
movement,
}
}
}
@@ -220,8 +140,10 @@ fn update_grounded(
});
if is_grounded {
info!("grounded");
commands.entity(entity).insert(Grounded);
} else {
info!("not grounded");
commands.entity(entity).remove::<Grounded>();
}
}
@@ -256,19 +178,22 @@ fn movement(
Has<Grounded>,
)>,
rig_transform_q: Option<Single<&GlobalTransform, With<PlayerRig>>>,
mut jump_used: Local<bool>,
) {
let delta_time = time.delta_secs();
let mut direction = controls.keyboard_state.move_dir;
let mut jump_requested = controls.keyboard_state.jump;
if let Some(gamepad) = controls.gamepad_state {
direction += gamepad.move_dir;
direction = direction.normalize_or_zero();
jump_requested |= gamepad.jump;
}
direction = direction.normalize_or_zero();
for (movement_acceleration, jump_impulse, mut linear_velocity, is_grounded) in &mut controllers
{
let mut direction = direction.extend(0.0).xzy();
@@ -278,11 +203,22 @@ fn movement(
(rig_transform.forward() * direction.z) + (rig_transform.right() * direction.x);
}
linear_velocity.x -= direction.x * movement_acceleration.0 * delta_time;
linear_velocity.z -= direction.z * 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;
if is_grounded && jump_requested {
if is_grounded && jump_requested && !*jump_used {
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.
fn apply_gravity(
time: Res<Time>,
mut controllers: Query<(&ControllerGravity, &mut LinearVelocity)>,
mut controllers: Query<(&ControllerGravity, &mut LinearVelocity, Option<&Grounded>)>,
) {
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;
}
}
/// 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},
control::{
Controls,
controller::{CharacterControllerBundle, PlayerMovement},
controller::{CharacterControllerBundle, MovementBundle, PlayerMovement},
},
heads_ui::HeadChanged,
loading_assets::GameAssets,
@@ -87,8 +87,7 @@ fn spawn(
let gravity = Vector::NEG_Y * 40.0;
let collider = Collider::capsule(0.9, 1.2);
let acceleration = 30.0;
let damping = 0.95;
let acceleration = 30.0 * 60.;
let jump_impulse = 18.0;
let max_slope_angle = (60.0 as Scalar).to_radians();
@@ -101,11 +100,10 @@ fn spawn(
Visibility::default(),
// LockedAxes::ROTATION_LOCKED, todo
CollisionLayers::new(LayerMask(GameLayer::Player.to_bits()), LayerMask::ALL),
CharacterControllerBundle::new(collider, gravity).with_movement(
acceleration,
damping,
jump_impulse,
max_slope_angle,
CharacterControllerBundle::new(
collider,
gravity,
MovementBundle::new(acceleration, jump_impulse, max_slope_angle),
),
))
.with_children(|parent| {