Skip to content

Commit

Permalink
Close #40: Merge branch 'feature/40/gravity-based-up'
Browse files Browse the repository at this point in the history
  • Loading branch information
idanarye committed Oct 11, 2024
2 parents 79c7dc8 + ae033d6 commit 5ce6fea
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 59 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ NOTE: Subcrates have their own changelogs: [bevy-tnua-physics-integration-layer]
nullified even with very high walk acceleration settings (see
https://github.com/idanarye/bevy-tnua/issues/30)

### Changed
- Instead of fixating it to positive Y, Tnua now calculates the up direction to
be the reverse of the gravity direction (see see
https://github.com/idanarye/bevy-tnua/issues/40)
- [**BREAKING**] API changes:
- (only relevant for custom basis/actions) The `up_direction` of
`TnuaBasisContext` and `TnuaActionContext` is now a field instead of a
method.

## 0.19.0 - 2024-07-05
### Changed
- Upgrade to Bevy 0.14.
Expand Down
51 changes: 42 additions & 9 deletions demos/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use bevy::window::{PresentMode, PrimaryWindow};
use bevy_egui::{egui, EguiContexts, EguiPlugin};
#[allow(unused_imports)]
use bevy_tnua::math::AsF32;
use bevy_tnua::math::{float_consts, Float, Vector2, Vector3};
#[cfg(feature = "egui")]
use bevy_tnua::TnuaToggle;

Expand All @@ -40,11 +41,16 @@ impl<C: Component + UiTunable> Default for DemoUi<C> {
}
}

const GRAVITY_MAGNITUDE: Float = 9.81;

impl<C: Component + UiTunable> Plugin for DemoUi<C> {
fn build(&self, app: &mut App) {
#[cfg(feature = "egui")]
app.add_plugins(EguiPlugin);
app.insert_resource(DemoUiPhysicsBackendActive(true));
app.insert_resource(DemoUiPhysicsBackendSettings {
active: true,
gravity: Vector3::NEG_Y * GRAVITY_MAGNITUDE,
});
app.configure_sets(
Update,
DemoInfoUpdateSystemSet.after(bevy_tnua::TnuaUserControlsSystemSet),
Expand Down Expand Up @@ -98,7 +104,10 @@ impl<C: Component + UiTunable> Plugin for DemoUi<C> {

// NOTE: The demos are responsible for updating the physics backend
#[derive(Resource)]
pub struct DemoUiPhysicsBackendActive(pub bool);
pub struct DemoUiPhysicsBackendSettings {
pub active: bool,
pub gravity: Vector3,
}

#[derive(Component)]
pub struct TrackedEntity(pub String);
Expand All @@ -116,7 +125,7 @@ fn apply_selectors(
#[allow(clippy::type_complexity)]
fn ui_system<C: Component + UiTunable>(
mut egui_context: EguiContexts,
mut physics_backend_active: ResMut<DemoUiPhysicsBackendActive>,
mut physics_backend_settings: ResMut<DemoUiPhysicsBackendSettings>,
mut query: Query<(
Entity,
&TrackedEntity,
Expand Down Expand Up @@ -182,7 +191,19 @@ fn ui_system<C: Component + UiTunable>(
ui.label("Dash with Shift (while moving in a direction)");
});
level_selection.show_in_ui(ui);
ui.checkbox(&mut physics_backend_active.0, "Physics Backend Enabled");
ui.collapsing("Physics Backend", |ui| {
ui.checkbox(&mut physics_backend_settings.active, "Physics Enabled");
let mut gravity_angle = physics_backend_settings.gravity.truncate().to_angle();
ui.horizontal(|ui| {
ui.label("Gravity Angle:");
if ui.add(egui::Slider::new(&mut gravity_angle, -float_consts::PI..=0.0)).changed() {
physics_backend_settings.gravity = Vector2::from_angle(gravity_angle).extend(0.0) * GRAVITY_MAGNITUDE;
}
if ui.button("Reset").clicked() {
physics_backend_settings.gravity = Vector3::NEG_Y * GRAVITY_MAGNITUDE;
}
});
});
for (
entity,
TrackedEntity(name),
Expand Down Expand Up @@ -281,7 +302,7 @@ fn ui_system<C: Component + UiTunable>(
}

fn update_physics_active_from_ui(
setting_from_ui: Res<DemoUiPhysicsBackendActive>,
setting_from_ui: Res<DemoUiPhysicsBackendSettings>,
#[cfg(feature = "rapier2d")] mut config_rapier2d: Option<
ResMut<bevy_rapier2d::plugin::RapierConfiguration>,
>,
Expand All @@ -291,34 +312,46 @@ fn update_physics_active_from_ui(
#[cfg(feature = "avian2d")] mut physics_time_avian2d: Option<
ResMut<Time<avian2d::schedule::Physics>>,
>,
#[cfg(feature = "avian2d")] mut gravity_avian2d: Option<ResMut<avian2d::prelude::Gravity>>,
#[cfg(feature = "avian3d")] mut physics_time_avian3d: Option<
ResMut<Time<avian3d::schedule::Physics>>,
>,
#[cfg(feature = "avian3d")] mut gravity_avian3d: Option<ResMut<avian3d::prelude::Gravity>>,
) {
#[cfg(feature = "rapier2d")]
if let Some(config) = config_rapier2d.as_mut() {
config.physics_pipeline_active = setting_from_ui.0;
config.physics_pipeline_active = setting_from_ui.active;
config.gravity = setting_from_ui.gravity.truncate();
}
#[cfg(feature = "rapier3d")]
if let Some(config) = config_rapier3d.as_mut() {
config.physics_pipeline_active = setting_from_ui.0;
config.physics_pipeline_active = setting_from_ui.active;
config.gravity = setting_from_ui.gravity;
}
#[cfg(feature = "avian2d")]
if let Some(physics_time) = physics_time_avian2d.as_mut() {
use avian2d::schedule::PhysicsTime;
if setting_from_ui.0 {
if setting_from_ui.active {
physics_time.unpause();
} else {
physics_time.pause();
}
}
#[cfg(feature = "avian2d")]
if let Some(gravity) = gravity_avian2d.as_mut() {
gravity.0 = setting_from_ui.gravity.truncate();
}
#[cfg(feature = "avian3d")]
if let Some(physics_time) = physics_time_avian3d.as_mut() {
use avian3d::schedule::PhysicsTime;
if setting_from_ui.0 {
if setting_from_ui.active {
physics_time.unpause();
} else {
physics_time.pause();
}
}
#[cfg(feature = "avian3d")]
if let Some(gravity) = gravity_avian3d.as_mut() {
gravity.0 = setting_from_ui.gravity;
}
}
15 changes: 5 additions & 10 deletions src/basis_action_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,9 @@ pub struct TnuaBasisContext<'a> {

/// A sensor that tracks the distance of the character's center from the ground.
pub proximity_sensor: &'a TnuaProximitySensor,
}

impl TnuaBasisContext<'_> {
/// The direction considered as "up".
pub fn up_direction(&self) -> Dir3 {
Dir3::Y
}
pub up_direction: Dir3,
}

/// The main movement command of a character.
Expand Down Expand Up @@ -205,6 +201,9 @@ pub struct TnuaActionContext<'a> {
/// A sensor that tracks the distance of the character's center from the ground.
pub proximity_sensor: &'a TnuaProximitySensor,

/// The direction considered as "up".
pub up_direction: Dir3,

/// An accessor to the currently active basis.
pub basis: &'a dyn DynamicBasis,
}
Expand All @@ -227,17 +226,13 @@ impl<'a> TnuaActionContext<'a> {
frame_duration: self.frame_duration,
tracker: self.tracker,
proximity_sensor: self.proximity_sensor,
up_direction: self.up_direction,
}
}

pub fn frame_duration_as_duration(&self) -> Duration {
Duration::from_secs_f64(self.frame_duration.into())
}

/// The direction considered as "up".
pub fn up_direction(&self) -> Dir3 {
Dir3::Y
}
}

/// Input for [`TnuaAction::apply`] that informs it about the long-term feeding of the input.
Expand Down
4 changes: 2 additions & 2 deletions src/builtins/crouch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ impl TnuaAction for TnuaBuiltinCrouch {
let spring_force_boost = spring_force.calc_boost(ctx.frame_duration);
let impulse_boost = self.impulse_boost(spring_offset);
if spring_force_boost.length_squared() < impulse_boost.powi(2) {
TnuaVelChange::boost(impulse_boost * ctx.up_direction().adjust_precision())
TnuaVelChange::boost(impulse_boost * ctx.up_direction.adjust_precision())
} else {
spring_force
}
Expand All @@ -131,7 +131,7 @@ impl TnuaAction for TnuaBuiltinCrouch {
let mut set_vel_change = |vel_change: TnuaVelChange| {
motor
.lin
.cancel_on_axis(ctx.up_direction().adjust_precision());
.cancel_on_axis(ctx.up_direction.adjust_precision());
motor.lin += vel_change;
};

Expand Down
2 changes: 1 addition & 1 deletion src/builtins/dash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ impl TnuaAction for TnuaBuiltinDash {
};

if 0.0 < desired_forward.length_squared() {
let up = ctx.up_direction();
let up = ctx.up_direction;
let up = up.adjust_precision();
let current_forward = ctx.tracker.rotation.mul_vec3(Vector3::NEG_Z);
let rotation_along_up_axis = rotation_arc_around_axis(
Expand Down
2 changes: 1 addition & 1 deletion src/builtins/jump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ impl TnuaAction for TnuaBuiltinJump {
lifecycle_status: TnuaActionLifecycleStatus,
motor: &mut crate::TnuaMotor,
) -> TnuaActionLifecycleDirective {
let up = ctx.up_direction().adjust_precision();
let up = ctx.up_direction.adjust_precision();

if lifecycle_status.just_started() {
let mut calculator = SegmentedJumpInitialVelocityCalculator::new(self.height);
Expand Down
12 changes: 4 additions & 8 deletions src/builtins/knockback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,25 +149,21 @@ impl TnuaAction for TnuaBuiltinKnockback {
if let Some(force_forward) = self.force_forward {
let current_forward = ctx.tracker.rotation.mul_vec3(Vector3::NEG_Z);
let rotation_along_up_axis = rotation_arc_around_axis(
ctx.up_direction(),
ctx.up_direction,
current_forward,
force_forward.adjust_precision(),
)
.unwrap_or(0.0);
let desired_angvel = rotation_along_up_axis / ctx.frame_duration;

let existing_angvel = ctx
.tracker
.angvel
.dot(ctx.up_direction().adjust_precision());
let existing_angvel = ctx.tracker.angvel.dot(ctx.up_direction.adjust_precision());

let torque_to_turn = desired_angvel - existing_angvel;

motor
.ang
.cancel_on_axis(ctx.up_direction().adjust_precision());
motor.ang +=
TnuaVelChange::boost(torque_to_turn * ctx.up_direction().adjust_precision());
.cancel_on_axis(ctx.up_direction.adjust_precision());
motor.ang += TnuaVelChange::boost(torque_to_turn * ctx.up_direction.adjust_precision());
}

TnuaActionLifecycleDirective::StillActive
Expand Down
Loading

0 comments on commit 5ce6fea

Please sign in to comment.