Player motion and forces

This commit is contained in:
2025-06-24 16:49:59 -04:00
parent 1e70c0a42d
commit 8c3281f9cc
6 changed files with 114 additions and 10 deletions

View File

@@ -1,3 +1,4 @@
pub mod camera;
// pub mod character_controller;
pub mod player;
pub mod tags;

21
src/components/player.rs Normal file
View File

@@ -0,0 +1,21 @@
use bevy::prelude::*;
use bevy_rapier3d::prelude::GravityScale;
#[derive(Component, Default, Reflect)]
#[require(PlayerVelocity)]
pub struct PlayerMotion(pub Vec3);
#[derive(Component, Default, Reflect)]
pub struct PlayerForce(pub Vec3);
#[derive(Component, Default, Reflect)]
#[require(GravityScale)]
pub struct GravityDirection(pub Option<Dir3>);
impl GravityDirection {
pub const DOWN: GravityDirection = GravityDirection(Some(Dir3::NEG_Y));
pub const NONE: GravityDirection = GravityDirection(None);
}
#[derive(Component, Default, Reflect)]
pub struct PlayerVelocity(pub Vec3);

View File

@@ -1,6 +1,9 @@
use bevy::prelude::*;
use crate::components::player::*;
#[derive(Component, Reflect)]
#[require(PlayerMotion, PlayerForce, GravityDirection)]
pub struct Player;
#[derive(Component, Reflect)]

View File

@@ -1,6 +1,7 @@
use crate::{
components::{
camera::{CameraPitch, CameraRoot, FollowCam, MainCamera, Unfocused},
player::GravityDirection,
tags::{Player, Ship},
},
plugins::*,
@@ -47,6 +48,7 @@ fn setup_scene(
.spawn((
Name::new("Player"),
Player,
GravityDirection::DOWN,
Collider::capsule_y(0.5, 0.5),
RigidBody::KinematicPositionBased,
KinematicCharacterController::default(),

View File

@@ -1,22 +1,85 @@
use bevy::prelude::*;
use bevy_rapier3d::prelude::*;
use crate::components::tags::Player;
use crate::components::{
player::{GravityDirection, PlayerForce, PlayerMotion, PlayerVelocity},
tags::Player,
};
pub struct PlayerPlugin;
impl Plugin for PlayerPlugin {
fn build(&self, app: &mut App) {
app.add_systems(PreUpdate, keyboard_input);
app.add_systems(PreUpdate, keyboard_input.in_set(PlayerInputSystems));
app.add_systems(Update, (apply_gravity, apply_forces, apply_motion).chain());
}
}
#[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();
vel.0 += force.0 * time.delta_secs();
}
fn apply_gravity(
player: Single<
(
&mut PlayerVelocity,
&GravityDirection,
&GravityScale,
Option<&KinematicCharacterControllerOutput>,
),
With<Player>,
>,
time: Res<Time>,
) {
let (mut vel, dir, scale, output) = player.into_inner();
let Some(grav) = dir.0.map(|d| d.as_vec3()) else {
return;
};
let is_grounded = output.map(|o| o.grounded).unwrap_or(false);
if !is_grounded {
vel.0 += grav * scale.0 * 9.47 * time.delta_secs();
} else {
vel.0 = vel.0 - vel.0.dot(grav) * grav;
}
}
fn apply_motion(
player: Single<
(
&mut KinematicCharacterController,
&Transform,
&PlayerVelocity,
&PlayerMotion,
),
With<Player>,
>,
time: Res<Time>,
) {
let (mut controller, transform, vel, motion) = player.into_inner();
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());
}
fn keyboard_input(
key: Res<ButtonInput<KeyCode>>,
mut player: Single<(&mut KinematicCharacterController, &mut Transform), With<Player>>,
time: Res<Time>,
player: Single<
(
&mut PlayerMotion,
&mut PlayerVelocity,
&Transform,
Option<&KinematicCharacterControllerOutput>,
),
With<Player>,
>,
) {
let (mut controller, mut transform) = player.into_inner();
let (mut motion, mut vel, transform, output) = player.into_inner();
let mut move_vec = Vec3::ZERO;
if key.pressed(KeyCode::KeyW) {
@@ -31,6 +94,11 @@ fn keyboard_input(
move_vec.x = 1.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;
}
let angle = if key.pressed(KeyCode::KeyQ) {
-0.1
} else if key.pressed(KeyCode::KeyE) {
@@ -38,8 +106,10 @@ fn keyboard_input(
} else {
0.0
};
transform.rotate_z(angle * time.delta_secs());
controller.up = transform.up().as_vec3();
move_vec += transform.down().as_vec3();
controller.translation = Some(move_vec * time.delta_secs());
motion.0 = move_vec;
// transform.rotate_z(angle * time.delta_secs());
// controller.up = transform.up().as_vec3();
// move_vec += transform.down().as_vec3();
// controller.translation = Some(move_vec * time.delta_secs());
}

View File

@@ -1,6 +1,9 @@
use bevy::prelude::*;
use crate::components::camera::{FollowCam, FollowTarget};
use crate::components::{
camera::{FollowCam, FollowTarget},
player::{GravityDirection, PlayerForce, PlayerMotion, PlayerVelocity},
};
pub struct TypesPlugin;
@@ -8,5 +11,9 @@ impl Plugin for TypesPlugin {
fn build(&self, app: &mut App) {
app.register_type::<FollowTarget>();
app.register_type::<FollowCam>();
app.register_type::<PlayerVelocity>();
app.register_type::<PlayerForce>();
app.register_type::<PlayerMotion>();
app.register_type::<GravityDirection>();
}
}