From b2138d3e4cae1369a438e66be1e6d1340d565c86 Mon Sep 17 00:00:00 2001 From: Nolan Darilek Date: Sun, 16 May 2021 17:24:26 -0500 Subject: [PATCH] Describe directions relatively. --- src/core.rs | 49 ++++++++++++++++++++++++++++++++++++++++------ src/exploration.rs | 2 +- src/visibility.rs | 12 +++++++----- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/core.rs b/src/core.rs index c2b597f..98c564f 100644 --- a/src/core.rs +++ b/src/core.rs @@ -1,6 +1,7 @@ use std::{ cmp::{max, min}, fmt::Display, + ops::Sub, }; use bevy::{core::FloatOrd, prelude::*, transform::TransformSystem}; @@ -94,6 +95,23 @@ impl Angle { } } +impl Sub for Angle { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + match self { + Angle::Degrees(v1) => match rhs { + Angle::Degrees(v2) => Angle::Degrees(v1 - v2), + Angle::Radians(v2) => Angle::Degrees(v1 - v2.to_degrees()), + }, + Angle::Radians(v1) => match rhs { + Angle::Degrees(v2) => Angle::Radians(v1 - v2.to_radians()), + Angle::Radians(v2) => Angle::Radians(v1 - v2), + }, + } + } +} + #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum MovementDirection { North, @@ -282,23 +300,42 @@ pub trait PointLike { self.distance_squared(other).sqrt() } - fn bearing(&self, other: &dyn PointLike) -> f32 { + fn bearing(&self, other: &dyn PointLike) -> Angle { let y = other.y() - self.y(); let x = other.x() - self.x(); - y.atan2(x) + Angle::Radians(y.atan2(x)) } fn direction(&self, other: &dyn PointLike) -> MovementDirection { - let heading = self.bearing(other); - MovementDirection::new(heading.to_degrees()) + self.bearing(other).into() } - fn direction_and_distance(&self, other: &dyn PointLike) -> String { + fn direction_and_distance(&self, other: &dyn PointLike, yaw: Option) -> String { let mut tokens: Vec = vec![]; let distance = self.distance(other).round() as i32; if distance > 0 { let tile_or_tiles = if distance == 1 { "tile" } else { "tiles" }; - let direction: String = self.direction(other).into(); + let direction: String = if let Some(yaw) = yaw { + let bearing = self.bearing(other); + let relative = (bearing - yaw).degrees(); + match relative { + v if v <= 15. => "ahead".into(), + v if v <= 45. => "ahead and left".into(), + v if v <= 75. => "left and ahead".into(), + v if v <= 105. => "left".into(), + v if v <= 135. => "left and behind".into(), + v if v <= 165. => "behind and left".into(), + v if v <= 195. => "behind".into(), + v if v <= 225. => "behind and right".into(), + v if v <= 255. => "right and behind".into(), + v if v <= 285. => "right".into(), + v if v <= 315. => "right and ahead".into(), + v if v <= 345. => "ahead and right".into(), + _ => "ahead".into(), + } + } else { + self.direction(other).into() + }; tokens.push(format!("{} {} {}", direction, distance, tile_or_tiles)); } tokens.join(" ") diff --git a/src/exploration.rs b/src/exploration.rs index f3e712f..6cae8c9 100644 --- a/src/exploration.rs +++ b/src/exploration.rs @@ -341,7 +341,7 @@ fn exploration_changed_announcement( } else { "Unknown".to_string() }; - let mut tokens: Vec = vec![coordinates.direction_and_distance(exploring)]; + let mut tokens: Vec = vec![coordinates.direction_and_distance(exploring, None)]; if fog_of_war { tokens.push("in the fog of war".into()); } diff --git a/src/visibility.rs b/src/visibility.rs index 5974ac6..5ee4236 100644 --- a/src/visibility.rs +++ b/src/visibility.rs @@ -6,7 +6,7 @@ use derive_more::{Deref, DerefMut}; use shadowcast::{vision_distance, Context, InputGrid}; use crate::{ - core::{Coordinates, Player, PointLike}, + core::{Angle, Coordinates, Player, PointLike}, log::Log, map::{ITileType, Map, MapConfig}, }; @@ -222,7 +222,7 @@ fn log_visible( mut seen: Local>, mut recently_lost: Local>, mut log: Query<&mut Log>, - viewers: Query<(&Viewshed, &Coordinates, &Player)>, + viewers: Query<(&Viewshed, &Coordinates, &Transform), With>, map: Query<&Map>, names: Query<&Name>, players: Query<&Player>, @@ -238,7 +238,7 @@ fn log_visible( } let mut new_seen = HashSet::new(); if let Ok(mut log) = log.single_mut() { - for (viewshed, coordinates, _) in viewers.iter() { + for (viewshed, coordinates, transform) in viewers.iter() { for viewed_coordinates in &viewshed.visible { for map in map.iter() { let index = viewed_coordinates.to_index(map.width()); @@ -250,8 +250,10 @@ fn log_visible( if players.get(*entity).is_err() { if !seen.contains(&*entity) { let name = name.to_string(); - let location = - coordinates.direction_and_distance(viewed_coordinates); + let forward = transform.local_x(); + let yaw = Angle::Radians(forward.y.atan2(forward.x)); + let location = coordinates + .direction_and_distance(viewed_coordinates, Some(yaw)); log.push(format!("{}: {}", name, location)); } new_seen.insert(*entity);