From 3876c58a25ed1cb4afebe804ff1590204992575a Mon Sep 17 00:00:00 2001 From: Jakob Stechow Date: Sun, 26 Oct 2025 11:44:42 +0100 Subject: [PATCH 1/7] wip: basic climbing slopes --- assets/blender_src/fun_shooter.blend | 2 +- assets/blender_src/fun_shooter.blend1 | 2 +- src/character_controller/mod.rs | 112 ++++++++++++++++++++++++++ src/enemy/spawn/mod.rs | 4 +- src/kinematic_controller/mod.rs | 95 ---------------------- src/main.rs | 8 +- src/nav_mesh_pathfinding/mod.rs | 58 ++++++------- src/player/movement/mod.rs | 57 ++++++++----- src/player/spawn/mod.rs | 4 +- 9 files changed, 188 insertions(+), 154 deletions(-) create mode 100644 src/character_controller/mod.rs delete mode 100644 src/kinematic_controller/mod.rs diff --git a/assets/blender_src/fun_shooter.blend b/assets/blender_src/fun_shooter.blend index 3a58104..0d3b466 100644 --- a/assets/blender_src/fun_shooter.blend +++ b/assets/blender_src/fun_shooter.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:13cd38a7fba85aa1fd7c3825d2203ea436e47d24eb3d327b4c9632a43e72b955 +oid sha256:794adc3aa328ac508bba89c4a02a95732c83528f67243eb6a8474c67899da195 size 109793554 diff --git a/assets/blender_src/fun_shooter.blend1 b/assets/blender_src/fun_shooter.blend1 index 019340b..3a58104 100644 --- a/assets/blender_src/fun_shooter.blend1 +++ b/assets/blender_src/fun_shooter.blend1 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9c1eb5795fcfd04457b198ba49b9d066fe9719445eb575cd571e7417163a7c93 +oid sha256:13cd38a7fba85aa1fd7c3825d2203ea436e47d24eb3d327b4c9632a43e72b955 size 109793554 diff --git a/src/character_controller/mod.rs b/src/character_controller/mod.rs new file mode 100644 index 0000000..e396e1c --- /dev/null +++ b/src/character_controller/mod.rs @@ -0,0 +1,112 @@ +use avian3d::prelude::*; +use bevy::prelude::*; + +use crate::GRAVITY; + +const CAPSULE_RADIUS: f32 = 0.2; +const CAPSULE_LENGTH: f32 = 1.3; + +/// Contains all needed components for a character that should be controlled by the player +#[derive(Bundle)] +pub struct CharacterControllerBundle { + velocity: LinearVelocity, + rigid_body: RigidBody, + collider: Collider, + grounded: Grounded, + locked_axes: LockedAxes, +} + +impl Default for CharacterControllerBundle { + fn default() -> Self { + Self { + velocity: LinearVelocity::ZERO, + rigid_body: RigidBody::Kinematic, + collider: Collider::capsule(CAPSULE_RADIUS, CAPSULE_LENGTH), + grounded: Grounded::default(), + locked_axes: LockedAxes::new() + .lock_rotation_x() + .lock_rotation_y() + .lock_rotation_z(), + } + } +} + +#[derive(Component)] +pub struct Grounded(pub bool); + +impl Default for Grounded { + fn default() -> Self { + Self(true) + } +} + +pub struct CharacterControllerPlugin; + +impl Plugin for CharacterControllerPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Update, (update_on_ground, apply_gravity_over_time)); + } +} + +fn update_on_ground( + query: Query<(&Transform, Entity, &mut LinearVelocity, &mut Grounded)>, + spatial_query: SpatialQuery, +) { + for (transform, entity, mut velocity, mut grounded) in query { + let on_ground = spatial_query + .cast_shape( + &Collider::capsule(CAPSULE_RADIUS, CAPSULE_LENGTH), + transform.translation, + transform.rotation, + Dir3::NEG_Y, + &ShapeCastConfig { + max_distance: 0.1, + ..default() + }, + &SpatialQueryFilter::default().with_excluded_entities([entity]), + ) + .is_some(); + if grounded.0 != on_ground { + grounded.0 = on_ground; + } + + if on_ground && velocity.y <= 0.0 { + velocity.y = 0.0; + } + } +} + +fn apply_gravity_over_time( + query: Query<(&Grounded, &mut LinearVelocity)>, + time: Res