Compare commits

...

4 Commits

Author SHA1 Message Date
1fb194266c Update direction in PreUpdate.
Some checks failed
continuous-integration/drone/push Build is failing
2022-08-04 14:30:40 -05:00
e1a1522269 Correctly calculate direction and distance with yaws. 2022-08-04 14:30:07 -05:00
1fcec80e0e Add system for limiting speed. 2022-08-04 11:49:17 -05:00
c02f9b21d6 Navigation cleanup. 2022-08-04 11:25:09 -05:00
2 changed files with 105 additions and 102 deletions

View File

@ -493,15 +493,13 @@ impl GlobalTransformExt for GlobalTransform {
) -> String { ) -> String {
use bevy::math::Vec3Swizzles; use bevy::math::Vec3Swizzles;
let scale = PHYSICS_SCALE.read().unwrap(); let scale = PHYSICS_SCALE.read().unwrap();
let (_, rotation, _) = self.to_scale_rotation_translation();
let pos1 = Isometry::new( let pos1 = Isometry::new(
(self.translation() / *scale).xy().into(), (self.translation() / *scale).xy().into(),
rotation.to_scaled_axis().z, self.yaw().radians(),
); );
let (_, other_rotation, _) = self.to_scale_rotation_translation();
let pos2 = Isometry::new( let pos2 = Isometry::new(
(other.translation() / *scale).xy().into(), (other.translation() / *scale).xy().into(),
other_rotation.to_scaled_axis().z, other.yaw().radians(),
); );
let closest = let closest =
closest_points(&pos1, &*collider.raw, &pos2, &*other_collider.raw, f32::MAX).unwrap(); closest_points(&pos1, &*collider.raw, &pos2, &*other_collider.raw, f32::MAX).unwrap();

View File

@ -1,4 +1,7 @@
use std::{error::Error, f32::consts::PI, fmt::Debug, hash::Hash, marker::PhantomData}; use std::{
collections::HashMap, error::Error, f32::consts::PI, fmt::Debug, hash::Hash,
marker::PhantomData,
};
use bevy::prelude::*; use bevy::prelude::*;
use bevy_rapier2d::prelude::*; use bevy_rapier2d::prelude::*;
@ -50,31 +53,30 @@ impl Default for RotationSpeed {
#[reflect(Component)] #[reflect(Component)]
pub struct Speed(pub f32); pub struct Speed(pub f32);
#[derive(Component, Clone, Copy, Debug, Default, Reflect)] #[derive(Component, Deref, DerefMut)]
#[reflect(Component)] struct SnapTimer(Timer);
pub struct Sprinting;
#[derive(Default, Deref, DerefMut)] impl Default for SnapTimer {
struct Snapping(bool); fn default() -> Self {
Self(Timer::from_seconds(0.25, false))
}
}
fn movement_controls<S>( fn movement_controls<S>(
mut commands: Commands, mut commands: Commands,
config: Res<NavigationConfig<S>>, config: Res<NavigationConfig<S>>,
time: Res<Time>, time: Res<Time>,
mut snapping: ResMut<Snapping>, snap_timers: Res<HashMap<Entity, SnapTimer>>,
mut query: Query< mut query: Query<(
( Entity,
Entity, &ActionState<NavigationAction>,
&ActionState<NavigationAction>, &mut Velocity,
&mut Velocity, &mut Speed,
&mut Speed, &MaxSpeed,
&MaxSpeed, Option<&RotationSpeed>,
Option<&RotationSpeed>, &mut Transform,
&mut Transform, Option<&Destination>,
Option<&Destination>, )>,
),
With<Player>,
>,
exploration_focused: Query<Entity, With<ExplorationFocused>>, exploration_focused: Query<Entity, With<ExplorationFocused>>,
) where ) where
S: 'static + Clone + Debug + Eq + Hash + Send + Sync, S: 'static + Clone + Debug + Eq + Hash + Send + Sync,
@ -90,50 +92,46 @@ fn movement_controls<S>(
destination, destination,
) in &mut query ) in &mut query
{ {
if **snapping { let sprinting = actions.pressed(NavigationAction::Sprint);
if actions.pressed(NavigationAction::Rotate) { let mut cleanup = false;
continue; if actions.pressed(NavigationAction::Move) {
} if let Some(pair) = actions.clamped_axis_pair(NavigationAction::Move) {
**snapping = false; cleanup = true;
continue; let direction = pair.xy();
} else { let forward_backward_movement_factor = if direction.x > 0. {
let sprinting = actions.pressed(NavigationAction::Sprint); config.forward_movement_factor
if sprinting { } else if direction.x < 0. {
commands.entity(entity).insert(Sprinting); config.backward_movement_factor
} else { } else {
commands.entity(entity).remove::<Sprinting>(); 0.
} };
let mut cleanup = false; let movement_factor = if direction.x != 0. && direction.y != 0. {
if actions.pressed(NavigationAction::Move) { config
if let Some(pair) = actions.clamped_axis_pair(NavigationAction::Move) { .strafe_movement_factor
cleanup = true; .min(forward_backward_movement_factor)
let mut direction = pair.xy(); } else if direction.y != 0. {
let strength = direction.length(); config.strafe_movement_factor
if direction.x > 0. { } else {
direction.x *= config.forward_movement_factor; forward_backward_movement_factor
} else if direction.x < 0. { };
direction.x *= config.backward_movement_factor; let mut s = if sprinting {
} **max_speed
if direction.y != 0. { } else {
direction.y *= config.strafe_movement_factor; **max_speed / config.sprint_movement_factor
} };
let s = if sprinting { s *= movement_factor;
**max_speed **speed = s;
} else { let mut v = direction * **speed;
**max_speed / config.sprint_movement_factor v = transform
}; .compute_matrix()
**speed = s; .transform_vector3(v.extend(0.))
direction *= strength; .truncate();
let mut v = direction * **speed; velocity.linvel = v;
v = transform
.compute_matrix()
.transform_vector3(v.extend(0.))
.truncate();
velocity.linvel = v;
}
} else if destination.is_none() {
velocity.linvel = Vec2::ZERO;
} }
} else if destination.is_none() {
velocity.linvel = Vec2::ZERO;
}
if !snap_timers.contains_key(&entity) {
if let Some(rotation_speed) = rotation_speed { if let Some(rotation_speed) = rotation_speed {
if actions.pressed(NavigationAction::Rotate) { if actions.pressed(NavigationAction::Rotate) {
cleanup = true; cleanup = true;
@ -145,22 +143,25 @@ fn movement_controls<S>(
} else { } else {
velocity.angvel = 0.; velocity.angvel = 0.;
} }
if cleanup { } else {
commands.entity(entity).remove::<Destination>(); velocity.angvel = 0.;
commands.entity(entity).remove::<Exploring>(); }
for entity in exploration_focused.iter() { if cleanup {
commands.entity(entity).remove::<ExplorationFocused>(); commands.entity(entity).remove::<Destination>();
} commands.entity(entity).remove::<Exploring>();
for entity in exploration_focused.iter() {
commands.entity(entity).remove::<ExplorationFocused>();
} }
} }
} }
} }
fn snap<S>( fn snap(
mut tts: ResMut<Tts>, mut tts: ResMut<Tts>,
mut snapping: ResMut<Snapping>, mut snap_timers: ResMut<HashMap<Entity, SnapTimer>>,
mut query: Query< mut query: Query<
( (
Entity,
&ActionState<NavigationAction>, &ActionState<NavigationAction>,
&mut Transform, &mut Transform,
&mut Velocity, &mut Velocity,
@ -168,33 +169,32 @@ fn snap<S>(
), ),
With<Player>, With<Player>,
>, >,
) -> Result<(), Box<dyn Error>> ) -> Result<(), Box<dyn Error>> {
where for (entity, actions, mut transform, mut velocity, direction) in query.iter_mut() {
S: 'static + Copy + Debug + Eq + Hash + Send + Sync,
{
for (actions, mut transform, mut velocity, direction) in query.iter_mut() {
if actions.just_pressed(NavigationAction::SnapLeft) { if actions.just_pressed(NavigationAction::SnapLeft) {
**snapping = true; println!("snap left");
snap_timers.insert(entity, SnapTimer::default());
transform.rotation = Quat::from_rotation_z(match direction { transform.rotation = Quat::from_rotation_z(match direction {
CardinalDirection::North => PI, CardinalDirection::North => PI,
CardinalDirection::East => PI / 2., CardinalDirection::East => PI / 2.,
CardinalDirection::South => 0., CardinalDirection::South => 0.,
CardinalDirection::West => PI * 1.5, CardinalDirection::West => -PI / 2.,
}); });
velocity.angvel = 0.; velocity.angvel = 0.;
} }
if actions.just_pressed(NavigationAction::SnapRight) { if actions.just_pressed(NavigationAction::SnapRight) {
**snapping = true; println!("Snap right");
snap_timers.insert(entity, SnapTimer::default());
transform.rotation = Quat::from_rotation_z(match direction { transform.rotation = Quat::from_rotation_z(match direction {
CardinalDirection::North => 0., CardinalDirection::North => 0.,
CardinalDirection::East => PI * 1.5, CardinalDirection::East => -PI / 2.,
CardinalDirection::South => PI, CardinalDirection::South => PI,
CardinalDirection::West => PI / 2., CardinalDirection::West => PI / 2.,
}); });
velocity.angvel = 0.; velocity.angvel = 0.;
} }
if actions.just_pressed(NavigationAction::SnapCardinal) { if actions.just_pressed(NavigationAction::SnapCardinal) {
**snapping = true; snap_timers.insert(entity, SnapTimer::default());
let yaw: Angle = direction.into(); let yaw: Angle = direction.into();
let yaw = yaw.radians(); let yaw = yaw.radians();
transform.rotation = Quat::from_rotation_z(yaw); transform.rotation = Quat::from_rotation_z(yaw);
@ -202,7 +202,7 @@ where
tts.speak(direction.to_string(), true)?; tts.speak(direction.to_string(), true)?;
} }
if actions.just_pressed(NavigationAction::SnapReverse) { if actions.just_pressed(NavigationAction::SnapReverse) {
**snapping = true; snap_timers.insert(entity, SnapTimer::default());
transform.rotate(Quat::from_rotation_z(PI)); transform.rotate(Quat::from_rotation_z(PI));
velocity.angvel = 0.; velocity.angvel = 0.;
} }
@ -210,6 +210,13 @@ where
Ok(()) Ok(())
} }
fn tick_snap_timers(time: Res<Time>, mut snap_timers: ResMut<HashMap<Entity, SnapTimer>>) {
for timer in snap_timers.values_mut() {
timer.tick(time.delta());
}
snap_timers.retain(|_, v| !v.finished());
}
fn update_direction( fn update_direction(
mut commands: Commands, mut commands: Commands,
mut query: Query< mut query: Query<
@ -263,6 +270,14 @@ fn add_speed(mut commands: Commands, query: Query<Entity, (Added<Speed>, Without
} }
} }
fn limit_speed(mut query: Query<(&mut Speed, &MaxSpeed)>) {
for (mut speed, max_speed) in &mut query {
if **speed > **max_speed {
**speed = **max_speed;
}
}
}
fn remove_speed(removed: RemovedComponents<Speed>, mut query: Query<&mut Velocity>) { fn remove_speed(removed: RemovedComponents<Speed>, mut query: Query<&mut Velocity>) {
for entity in removed.iter() { for entity in removed.iter() {
if let Ok(mut velocity) = query.get_mut(entity) { if let Ok(mut velocity) = query.get_mut(entity) {
@ -362,39 +377,29 @@ where
.get_resource::<NavigationConfig<S>>() .get_resource::<NavigationConfig<S>>()
.unwrap() .unwrap()
.clone(); .clone();
const SNAP: &str = "SNAP"; app.init_resource::<HashMap<Entity, SnapTimer>>()
app.init_resource::<Snapping>()
.register_type::<MaxSpeed>() .register_type::<MaxSpeed>()
.register_type::<RotationSpeed>() .register_type::<RotationSpeed>()
.register_type::<Sprinting>()
.add_plugin(InputManagerPlugin::<NavigationAction>::default()) .add_plugin(InputManagerPlugin::<NavigationAction>::default())
.add_system_to_stage(CoreStage::PostUpdate, update_direction) .add_system_to_stage(CoreStage::PreUpdate, update_direction)
.add_system_to_stage(CoreStage::PostUpdate, remove_direction) .add_system_to_stage(CoreStage::PostUpdate, remove_direction)
.add_system(tick_snap_timers)
.add_system(speak_direction.chain(error_handler)) .add_system(speak_direction.chain(error_handler))
.add_system(add_speed) .add_system(add_speed)
.add_system(limit_speed)
.add_system_to_stage(CoreStage::PostUpdate, remove_speed) .add_system_to_stage(CoreStage::PostUpdate, remove_speed)
.add_system_to_stage(CoreStage::PostUpdate, log_area_descriptions::<S, A>); .add_system_to_stage(CoreStage::PostUpdate, log_area_descriptions::<S, A>);
const MOVEMENT_CONTROLS: &str = "MOVEMENT_CONTROLS"; const MOVEMENT_CONTROLS: &str = "MOVEMENT_CONTROLS";
if config.movement_control_states.is_empty() { if config.movement_control_states.is_empty() {
app.add_system(movement_controls::<S>.label(MOVEMENT_CONTROLS)) app.add_system(movement_controls::<S>.label(MOVEMENT_CONTROLS))
.add_system( .add_system(snap.chain(error_handler).before(MOVEMENT_CONTROLS));
snap::<S>
.chain(error_handler)
.label(SNAP)
.before(MOVEMENT_CONTROLS),
);
} else { } else {
let states = config.movement_control_states; let states = config.movement_control_states;
for state in states { for state in states {
app.add_system_set( app.add_system_set(
SystemSet::on_update(state) SystemSet::on_update(state)
.with_system(movement_controls::<S>.label(MOVEMENT_CONTROLS)) .with_system(movement_controls::<S>.label(MOVEMENT_CONTROLS))
.with_system( .with_system(snap.chain(error_handler).before(MOVEMENT_CONTROLS)),
snap::<S>
.chain(error_handler)
.label(SNAP)
.before(MOVEMENT_CONTROLS),
),
); );
} }
} }