diff --git a/game_core/src/debug/mod.rs b/game_core/src/debug/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..81957b18619cec9a4b05c7057c7c52e2d6a9a016 --- /dev/null +++ b/game_core/src/debug/mod.rs @@ -0,0 +1,20 @@ +mod _plugin { + use crate::system::AppState; + use bevy::prelude::*; + use bevy_rapier2d::prelude::*; + + pub struct DebugPlugin; + impl Plugin for DebugPlugin { + fn build(&self, app: &mut App) { + app.add_systems(OnEnter(AppState::InGame), |mut commands: Commands| { + commands.spawn(( + TransformBundle::from_transform(Transform::from_xyz(0.0, -400.0, 0.0)), + RigidBody::Fixed, + Collider::cuboid(200.0, 50.0), + )); + }); + } + } +} + +pub use _plugin::DebugPlugin; diff --git a/game_core/src/entities/mod.rs b/game_core/src/entities/mod.rs index a25fe93b22ad8b77f7d89c34f4ee3c0e85024026..e48802a3597b3dc6e68860ceaea9ad93df362263 100644 --- a/game_core/src/entities/mod.rs +++ b/game_core/src/entities/mod.rs @@ -1,3 +1,4 @@ +mod physics; mod player; mod _plugin { @@ -7,9 +8,12 @@ mod _plugin { pub struct EntityPluginSet; impl PluginGroup for EntityPluginSet { fn build(self) -> PluginGroupBuilder { - PluginGroupBuilder::start::<Self>().add(super::player::PlayerSetupPlugin) + PluginGroupBuilder::start::<Self>() + .add(super::player::PlayerSetupPlugin) + .add(super::physics::PhysicsPlugin) } } } pub use _plugin::EntityPluginSet; +pub use physics::{Acceleration, PhysicsLimits, PhysicsSet, Velocity, GRAVITY_ACC, GRAVITY_VEC}; diff --git a/game_core/src/entities/physics.rs b/game_core/src/entities/physics.rs new file mode 100644 index 0000000000000000000000000000000000000000..c862b46e1dca3c87e8c35d5f32bd449ad22abff1 --- /dev/null +++ b/game_core/src/entities/physics.rs @@ -0,0 +1,83 @@ +use crate::system::run_in_game; +use bevy::prelude::*; +use bevy_rapier2d::prelude::KinematicCharacterController; + +pub const GRAVITY_ACC: f32 = -384.0; +pub const GRAVITY_VEC: Vec2 = Vec2::new(0.0, GRAVITY_ACC); + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, SystemSet)] +pub struct PhysicsSet; + +#[derive(Component, Clone, Copy, Debug, Default, Deref, DerefMut)] +pub struct Velocity(Vec2); + +#[derive(Component, Clone, Copy, Debug, Default, Deref, DerefMut)] +pub struct Acceleration(Vec2); + +#[derive(Component, Clone, Copy, Debug, Default)] +pub struct PhysicsLimits { + pub velocity: (Option<Vec2>, Option<Vec2>), + pub acceleration: (Option<Vec2>, Option<Vec2>), +} + +impl PhysicsLimits { + pub fn limit_velocity(&self, velocity: Vec2) -> Vec2 { + match self.velocity { + (None, None) => velocity, + (Some(min), None) => velocity.max(min), + (None, Some(max)) => velocity.min(max), + (Some(min), Some(max)) => velocity.min(max).max(min), + } + } + pub fn limit_acceleration(&self, acceleration: Vec2) -> Vec2 { + match self.acceleration { + (None, None) => acceleration, + (Some(min), None) => acceleration.max(min), + (None, Some(max)) => acceleration.min(max), + (Some(min), Some(max)) => acceleration.min(max).max(min), + } + } +} + +impl Acceleration { + pub fn gravity() -> Self { + Acceleration(GRAVITY_VEC) + } +} + +fn apply_acceleration( + time: Res<Time>, + mut query: Query<(&mut Velocity, &Acceleration, Option<&PhysicsLimits>)>, +) { + let dt = time.delta_seconds(); + for (mut velocity, acceleration, limits) in &mut query { + **velocity += **acceleration * dt; + **velocity = limits + .copied() + .unwrap_or_default() + .limit_velocity(**velocity); + } +} + +fn apply_velocity_to_kinematics( + time: Res<Time>, + mut query: Query<(&mut KinematicCharacterController, &Velocity)>, +) { + let dt = time.delta_seconds(); + for (mut controller, velocity) in &mut query { + controller.translation = Some(**velocity * dt); + } +} + +pub struct PhysicsPlugin; +impl Plugin for PhysicsPlugin { + fn build(&self, app: &mut App) { + app.add_systems( + Update, + (apply_acceleration, apply_velocity_to_kinematics) + .chain() + .in_set(PhysicsSet) + .run_if(run_in_game), + ); + } +} diff --git a/game_core/src/entities/player.rs b/game_core/src/entities/player.rs index 0d81e7daed8d47398cbf8b79d00df82e72a61644..3a32b2d6eff8bc1607b2336f0c12eafee60e6250 100644 --- a/game_core/src/entities/player.rs +++ b/game_core/src/entities/player.rs @@ -2,25 +2,41 @@ use crate::assets::AssetHandles; use crate::system::AppState; use bevy::prelude::*; +use crate::entities::{Acceleration, PhysicsLimits, Velocity, GRAVITY_ACC}; use bevy_rapier2d::prelude::*; +#[derive(Component, Clone, Copy, Debug)] +pub struct Player; + pub fn spawn_player(mut commands: Commands, assets: Res<AssetHandles>) { - commands - .spawn((SpriteSheetBundle { + commands.spawn(( + Player, + SpriteSheetBundle { sprite: TextureAtlasSprite::new(3), texture_atlas: assets.atlas("beige_blob"), ..Default::default() - },)) - .with_children(|builder| { - builder.spawn(( - TransformBundle::from_transform(Transform::from_xyz(0.0, -32.0, 0.0)), + }, + RigidBody::KinematicPositionBased, + KinematicCharacterController { + custom_shape: Some(( Collider::capsule(Vec2::new(0.0, 8.0), Vec2::new(0.0, -48.0), 48.0), - KinematicCharacterController { - offset: CharacterLength::Absolute(0.01), - ..Default::default() - }, - )); - }); + Vec2::new(0.0, -32.0), + 0.0, + )), + snap_to_ground: Some(CharacterLength::Absolute(0.5)), + offset: CharacterLength::Absolute(0.03), + ..Default::default() + }, + Acceleration::gravity(), + Velocity::default(), + PhysicsLimits { + velocity: ( + Some(Vec2::new(f32::NEG_INFINITY, GRAVITY_ACC)), + Some(Vec2::new(f32::INFINITY, (-GRAVITY_ACC) * 2.0)), + ), + acceleration: Default::default(), + }, + )); } pub struct PlayerSetupPlugin; diff --git a/game_core/src/lib.rs b/game_core/src/lib.rs index 371b2e70e463b79c32995cdb7f32695a4f3fe76a..24db2312511538727a30c6c224c78a429b18b228 100644 --- a/game_core/src/lib.rs +++ b/game_core/src/lib.rs @@ -1,3 +1,4 @@ pub mod assets; +pub mod debug; pub mod entities; pub mod system; diff --git a/game_core/src/main.rs b/game_core/src/main.rs index ef41de509ec2a84276b781447bf48a85c3a0162e..acc48ff9faf53843b0732ccb07ba957d2bd57a67 100644 --- a/game_core/src/main.rs +++ b/game_core/src/main.rs @@ -5,6 +5,7 @@ fn main() { .add_plugins(game_core::assets::AssetLoadingPlugin) .add_plugins(game_core::system::SystemPluginSet) .add_plugins(game_core::entities::EntityPluginSet) + .add_plugins(game_core::debug::DebugPlugin) .add_plugins(bevy_rapier2d::plugin::RapierPhysicsPlugin::<()>::pixels_per_meter(128.0)) .add_plugins(micro_banimate::BanimatePluginGroup) .add_plugins(micro_musicbox::CombinedAudioPlugins::< diff --git a/game_core/src/system/mod.rs b/game_core/src/system/mod.rs index f8823a1a35381351ddc35538371c36968fb300c2..0cf6bb6dd0f72488ba6b0fb99d5326e15e074747 100644 --- a/game_core/src/system/mod.rs +++ b/game_core/src/system/mod.rs @@ -17,6 +17,7 @@ mod _plugin { pub struct PhysDebugPlugin; impl Plugin for PhysDebugPlugin { fn build(&self, app: &mut App) { + info!("Including Debug Physics Plugin"); app.add_plugins(bevy_rapier2d::render::RapierDebugRenderPlugin { mode: DebugRenderMode::all(), style: DebugRenderStyle::default(), @@ -36,6 +37,7 @@ mod _plugin { #[cfg(feature = "phys-debug")] { + info!("Rendering physics debug information"); plugins.add(phys_debug::PhysDebugPlugin) }