Refactor helpers for direction and distance, adding some that take colliders into account.
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Nolan Darilek 2022-07-19 11:24:45 -05:00
parent 2d00bbb2db
commit 1721dc98f8
3 changed files with 157 additions and 85 deletions

View File

@ -8,7 +8,7 @@ use std::{
}; };
use bevy::{core::FloatOrd, ecs::query::WorldQuery, prelude::*}; use bevy::{core::FloatOrd, ecs::query::WorldQuery, prelude::*};
use bevy_rapier2d::prelude::*; use bevy_rapier2d::{na, parry::query::ClosestPoints, prelude::*, rapier::math::Isometry};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -52,6 +52,74 @@ impl Angle {
Radians(v) => *v, Radians(v) => *v,
} }
} }
fn relative_desc(&self) -> String {
let mode = RELATIVE_DIRECTION_MODE.read().unwrap();
match self.degrees() {
v if v <= 15. => "ahead",
v if v <= 45. => {
if *mode == RelativeDirectionMode::ClockFacing {
"11:00"
} else {
"ahead and left"
}
}
v if v <= 75. => {
if *mode == RelativeDirectionMode::ClockFacing {
"10:00"
} else {
"left and ahead"
}
}
v if v <= 105. => "left",
v if v <= 135. => {
if *mode == RelativeDirectionMode::ClockFacing {
"8:00"
} else {
"left and behind"
}
}
v if v <= 165. => {
if *mode == RelativeDirectionMode::ClockFacing {
"7:00"
} else {
"behind and left"
}
}
v if v <= 195. => "behind",
v if v <= 225. => {
if *mode == RelativeDirectionMode::ClockFacing {
"5:00"
} else {
"behind and right"
}
}
v if v <= 255. => {
if *mode == RelativeDirectionMode::ClockFacing {
"4:00"
} else {
"right and behind"
}
}
v if v <= 285. => "right",
v if v <= 315. => {
if *mode == RelativeDirectionMode::ClockFacing {
"2:00"
} else {
"right and ahead"
}
}
v if v <= 345. => {
if *mode == RelativeDirectionMode::ClockFacing {
"1:00"
} else {
"ahead and right"
}
}
_ => "ahead",
}
.into()
}
} }
impl Sub for Angle { impl Sub for Angle {
@ -216,6 +284,8 @@ static RELATIVE_DIRECTION_MODE: Lazy<RwLock<RelativeDirectionMode>> = Lazy::new(
RwLock::new(v) RwLock::new(v)
}); });
static PHYSICS_SCALE: Lazy<RwLock<f32>> = Lazy::new(|| RwLock::new(1.));
pub trait PointLike { pub trait PointLike {
fn x(&self) -> f32; fn x(&self) -> f32;
@ -283,73 +353,8 @@ pub trait PointLike {
if distance > 0 { if distance > 0 {
let tile_or_tiles = if distance == 1 { "tile" } else { "tiles" }; let tile_or_tiles = if distance == 1 { "tile" } else { "tiles" };
let direction: String = if let Some(yaw) = yaw { let direction: String = if let Some(yaw) = yaw {
let mode = RELATIVE_DIRECTION_MODE.read().unwrap();
let bearing = self.bearing(other); let bearing = self.bearing(other);
let relative = (bearing - yaw).degrees(); (bearing - yaw).relative_desc()
match relative {
v if v <= 15. => "ahead",
v if v <= 45. => {
if *mode == RelativeDirectionMode::ClockFacing {
"11:00"
} else {
"ahead and left"
}
}
v if v <= 75. => {
if *mode == RelativeDirectionMode::ClockFacing {
"10:00"
} else {
"left and ahead"
}
}
v if v <= 105. => "left",
v if v <= 135. => {
if *mode == RelativeDirectionMode::ClockFacing {
"8:00"
} else {
"left and behind"
}
}
v if v <= 165. => {
if *mode == RelativeDirectionMode::ClockFacing {
"7:00"
} else {
"behind and left"
}
}
v if v <= 195. => "behind",
v if v <= 225. => {
if *mode == RelativeDirectionMode::ClockFacing {
"5:00"
} else {
"behind and right"
}
}
v if v <= 255. => {
if *mode == RelativeDirectionMode::ClockFacing {
"4:00"
} else {
"right and behind"
}
}
v if v <= 285. => "right",
v if v <= 315. => {
if *mode == RelativeDirectionMode::ClockFacing {
"2:00"
} else {
"right and ahead"
}
}
v if v <= 345. => {
if *mode == RelativeDirectionMode::ClockFacing {
"1:00"
} else {
"ahead and right"
}
}
_ => "ahead",
}
.into()
} else { } else {
self.direction(other).into() self.direction(other).into()
}; };
@ -460,6 +465,69 @@ impl From<&dyn PointLike> for (i32, i32) {
} }
} }
pub trait GlobalTransformExt {
fn yaw(&self) -> Angle;
fn collider_direction_and_distance(
&self,
collider: &Collider,
other: &GlobalTransform,
other_collider: &Collider,
) -> String;
}
impl GlobalTransformExt for GlobalTransform {
fn yaw(&self) -> Angle {
let forward = self.local_x();
Angle::Radians(forward.y.atan2(forward.x))
}
fn collider_direction_and_distance(
&self,
collider: &Collider,
other: &GlobalTransform,
other_collider: &Collider,
) -> String {
use bevy::math::Vec3Swizzles;
let scale = PHYSICS_SCALE.read().unwrap();
let pos1 = Isometry::new(
(self.translation / *scale).xy().into(),
self.rotation.to_scaled_axis().z,
);
let pos2 = Isometry::new(
(other.translation / *scale).xy().into(),
other.rotation.to_scaled_axis().z,
);
let closest = bevy_rapier2d::parry::query::closest_points(
&pos1,
&*collider.raw,
&pos2,
&*other_collider.raw,
f32::MAX,
)
.unwrap();
let distance: u32 = match closest {
ClosestPoints::Intersecting => 0,
ClosestPoints::WithinMargin(p1, p2) => na::distance(&p1, &p2) as u32,
ClosestPoints::Disjoint => 0,
};
let tile_or_tiles = if distance == 1 { "tile" } else { "tiles" };
if distance > 0 {
if let ClosestPoints::WithinMargin(p1, p2) = closest {
let p1 = (p1.x, p1.y);
let p2 = (p2.x, p2.y);
let bearing = p1.bearing(&p2);
let yaw = self.yaw();
let direction = (bearing - yaw).relative_desc();
format!("{direction} {distance} {tile_or_tiles}")
} else {
format!("{} {}", distance, tile_or_tiles)
}
} else {
format!("{} {}", distance, tile_or_tiles)
}
}
}
#[derive(Component, Clone, Copy, Debug, Default, Reflect)] #[derive(Component, Clone, Copy, Debug, Default, Reflect)]
#[reflect(Component)] #[reflect(Component)]
pub struct Player; pub struct Player;
@ -524,6 +592,8 @@ where
} }
fn setup(core_config: Res<CoreConfig>) { fn setup(core_config: Res<CoreConfig>) {
let mut scale = PHYSICS_SCALE.write().unwrap();
*scale = core_config.pixels_per_unit as f32;
let mut mode = RELATIVE_DIRECTION_MODE.write().unwrap(); let mut mode = RELATIVE_DIRECTION_MODE.write().unwrap();
*mode = core_config.relative_direction_mode; *mode = core_config.relative_direction_mode;
} }

View File

@ -7,7 +7,7 @@ use bevy_tts::Tts;
use crate::{ use crate::{
commands::RunIfExistsExt, commands::RunIfExistsExt,
core::{Angle, CardinalDirection, Player}, core::{Angle, CardinalDirection, Player, GlobalTransformExt},
error::error_handler, error::error_handler,
exploration::{ExplorationFocused, Exploring}, exploration::{ExplorationFocused, Exploring},
pathfinding::Destination, pathfinding::Destination,
@ -264,13 +264,12 @@ where
fn update_direction( fn update_direction(
mut commands: Commands, mut commands: Commands,
mut query: Query< mut query: Query<
(Entity, &Transform, Option<&mut CardinalDirection>), (Entity, &GlobalTransform, Option<&mut CardinalDirection>),
(With<Player>, Changed<Transform>), (With<Player>, Changed<Transform>),
>, >,
) { ) {
for (entity, transform, direction) in query.iter_mut() { for (entity, transform, direction) in query.iter_mut() {
let forward = transform.local_x(); let yaw = transform.yaw();
let yaw = Angle::Radians(forward.y.atan2(forward.x));
let new_direction: CardinalDirection = yaw.into(); let new_direction: CardinalDirection = yaw.into();
if let Some(mut direction) = direction { if let Some(mut direction) = direction {
if *direction != new_direction { if *direction != new_direction {

View File

@ -12,7 +12,7 @@ use shadowcast::{vision_distance, Context, InputGrid};
use crate::{ use crate::{
bevy_rapier2d::prelude::*, bevy_rapier2d::prelude::*,
commands::RunIfExistsExt, commands::RunIfExistsExt,
core::{Angle, Player, PointLike}, core::{GlobalTransformExt, Player, PointLike},
log::Log, log::Log,
map::{Map, MapConfig, MapObstruction}, map::{Map, MapConfig, MapObstruction},
}; };
@ -380,8 +380,8 @@ fn log_visible(
mut recently_lost: Local<HashMap<Entity, Timer>>, mut recently_lost: Local<HashMap<Entity, Timer>>,
mut events: EventReader<VisibilityChanged>, mut events: EventReader<VisibilityChanged>,
mut log: Query<&mut Log>, mut log: Query<&mut Log>,
viewers: Query<(Entity, &Transform), (With<Player>, With<Viewshed>)>, viewers: Query<(Entity, &GlobalTransform, Option<&Collider>), (With<Player>, With<Viewshed>)>,
visible: Query<(&Name, &Transform), Without<DontLogWhenVisible>>, visible: Query<(&Name, &GlobalTransform, Option<&Collider>), Without<DontLogWhenVisible>>,
) { ) {
for timer in recently_lost.values_mut() { for timer in recently_lost.values_mut() {
timer.tick(time.delta()); timer.tick(time.delta());
@ -392,21 +392,24 @@ fn log_visible(
VisibilityChanged::Gained { viewer, .. } => viewer, VisibilityChanged::Gained { viewer, .. } => viewer,
VisibilityChanged::Lost { viewer, .. } => viewer, VisibilityChanged::Lost { viewer, .. } => viewer,
}; };
if let Ok((viewer_entity, viewer_transform)) = viewers.get(*viewer) { if let Ok((viewer_entity, viewer_transform, viewer_collider)) = viewers.get(*viewer) {
if let VisibilityChanged::Gained { viewed, .. } = event { if let VisibilityChanged::Gained { viewed, .. } = event {
if *viewed == viewer_entity || recently_lost.contains_key(viewed) { if *viewed == viewer_entity || recently_lost.contains_key(viewed) {
continue; continue;
} }
if let Ok((name, transform)) = visible.get(*viewed) { if let Ok((name, viewed_transform, viewed_collider)) = visible.get(*viewed) {
let viewed_coordinates = (transform.translation.x, transform.translation.y); let location = if let (Some(viewer_collider), Some(viewed_collider)) =
let forward = viewer_transform.local_x(); (viewer_collider, viewed_collider)
let yaw = Angle::Radians(forward.y.atan2(forward.x)); {
let viewer_coordinates = ( viewer_transform.collider_direction_and_distance(
viewer_transform.translation.x, viewer_collider,
viewer_transform.translation.y, &viewed_transform,
); viewed_collider,
let location = )
viewer_coordinates.direction_and_distance(&viewed_coordinates, Some(yaw)); } else {
let yaw = viewer_transform.yaw();
viewer_transform.direction_and_distance(viewed_transform, Some(yaw))
};
if let Ok(mut log) = log.get_single_mut() { if let Ok(mut log) = log.get_single_mut() {
log.push(format!("{}: {location}", name)); log.push(format!("{}: {location}", name));
} }