2021-05-13 17:25:45 +00:00
|
|
|
use std::{
|
|
|
|
cmp::{max, min},
|
2021-07-26 21:07:34 +00:00
|
|
|
f32::consts::PI,
|
2021-05-13 17:25:45 +00:00
|
|
|
fmt::Display,
|
2021-11-29 18:29:45 +00:00
|
|
|
sync::RwLock,
|
2021-05-13 17:25:45 +00:00
|
|
|
};
|
|
|
|
|
2024-10-06 22:17:48 +00:00
|
|
|
use bevy::{
|
|
|
|
app::PluginGroupBuilder,
|
|
|
|
math::{CompassOctant, CompassQuadrant, FloatOrd},
|
|
|
|
prelude::*,
|
|
|
|
};
|
2022-07-19 16:56:41 +00:00
|
|
|
use bevy_rapier2d::{
|
2022-08-02 22:14:51 +00:00
|
|
|
parry::query::{closest_points, distance, ClosestPoints},
|
2022-07-19 16:56:41 +00:00
|
|
|
prelude::*,
|
2022-12-19 20:08:31 +00:00
|
|
|
rapier::{math::Isometry, prelude::Aabb},
|
2022-07-19 16:56:41 +00:00
|
|
|
};
|
2021-11-29 18:29:45 +00:00
|
|
|
use once_cell::sync::Lazy;
|
2021-06-02 16:40:40 +00:00
|
|
|
use rand::prelude::*;
|
2021-11-29 18:29:45 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2021-05-13 17:25:45 +00:00
|
|
|
|
2024-10-06 22:17:48 +00:00
|
|
|
fn relative_desc(rot: &Rot2) -> String {
|
|
|
|
let mode = RELATIVE_DIRECTION_MODE.read().unwrap();
|
|
|
|
match rot.as_radians() {
|
|
|
|
v if v <= PI / 12. && v > -PI / 12. => "ahead",
|
|
|
|
v if v <= PI / 4. && v > PI / 12. => {
|
|
|
|
if *mode == RelativeDirectionMode::ClockFacing {
|
|
|
|
"11:00"
|
|
|
|
} else {
|
|
|
|
"ahead and left"
|
2022-07-19 16:24:45 +00:00
|
|
|
}
|
2024-10-06 22:17:48 +00:00
|
|
|
}
|
|
|
|
v if v <= 3. * PI / 8. && v > PI / 4. => {
|
|
|
|
if *mode == RelativeDirectionMode::ClockFacing {
|
|
|
|
"10:00"
|
|
|
|
} else {
|
|
|
|
"left and ahead"
|
2022-07-19 16:24:45 +00:00
|
|
|
}
|
2024-10-06 22:17:48 +00:00
|
|
|
}
|
|
|
|
v if v <= 5. * PI / 8. && v > 3. * PI / 8. => "left",
|
|
|
|
v if v <= 3. * PI / 4. && v > 5. * PI / 8. => {
|
|
|
|
if *mode == RelativeDirectionMode::ClockFacing {
|
|
|
|
"8:00"
|
|
|
|
} else {
|
|
|
|
"left and behind"
|
2022-07-19 16:24:45 +00:00
|
|
|
}
|
2024-10-06 22:17:48 +00:00
|
|
|
}
|
|
|
|
v if v <= 11. * PI / 12. && v > 3. * PI / 4. => {
|
|
|
|
if *mode == RelativeDirectionMode::ClockFacing {
|
|
|
|
"7:00"
|
|
|
|
} else {
|
|
|
|
"behind and left"
|
2022-07-19 16:24:45 +00:00
|
|
|
}
|
2024-10-06 22:17:48 +00:00
|
|
|
}
|
|
|
|
v if v <= PI && v > 11. * PI / 12. || v > -PI && v <= -11. * PI / 12. => "behind",
|
|
|
|
v if v <= -3. * PI / 4. && v > -11. * PI / 12. => {
|
|
|
|
if *mode == RelativeDirectionMode::ClockFacing {
|
|
|
|
"5:00"
|
|
|
|
} else {
|
|
|
|
"behind and right"
|
2022-07-19 16:24:45 +00:00
|
|
|
}
|
2024-10-06 22:17:48 +00:00
|
|
|
}
|
|
|
|
v if v <= -5. * PI / 8. && v > -3. * PI / 4. => {
|
|
|
|
if *mode == RelativeDirectionMode::ClockFacing {
|
|
|
|
"4:00"
|
|
|
|
} else {
|
|
|
|
"right and behind"
|
2022-07-19 16:24:45 +00:00
|
|
|
}
|
2024-10-06 22:17:48 +00:00
|
|
|
}
|
|
|
|
v if v <= -3. * PI / 8. && v > -5. * PI / 8. => "right",
|
|
|
|
v if v <= -PI / 4. && v > -3. * PI / 8. => {
|
|
|
|
if *mode == RelativeDirectionMode::ClockFacing {
|
|
|
|
"2:00"
|
|
|
|
} else {
|
|
|
|
"right and ahead"
|
2022-07-19 16:24:45 +00:00
|
|
|
}
|
|
|
|
}
|
2024-10-06 22:17:48 +00:00
|
|
|
v if v <= -PI / 12. && v > -PI / 4. => {
|
|
|
|
if *mode == RelativeDirectionMode::ClockFacing {
|
|
|
|
"1:00"
|
|
|
|
} else {
|
|
|
|
"ahead and right"
|
|
|
|
}
|
2021-05-16 22:24:26 +00:00
|
|
|
}
|
2024-10-06 22:17:48 +00:00
|
|
|
_ => "ahead",
|
2021-05-16 22:24:26 +00:00
|
|
|
}
|
2024-10-06 22:17:48 +00:00
|
|
|
.into()
|
2021-05-16 22:24:26 +00:00
|
|
|
}
|
|
|
|
|
2024-10-06 22:17:48 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Deref, DerefMut, Reflect)]
|
|
|
|
pub struct MovementDirection(CompassOctant);
|
|
|
|
|
|
|
|
impl From<Rot2> for MovementDirection {
|
|
|
|
fn from(rot: Rot2) -> Self {
|
|
|
|
use CompassOctant::*;
|
|
|
|
MovementDirection(match rot.as_radians() {
|
|
|
|
h if h > -PI / 8. && h <= PI / 8. => East,
|
|
|
|
h if h > PI / 8. && h <= 3. * PI / 8. => NorthEast,
|
|
|
|
h if h > 3. * PI / 8. && h <= 5. * PI / 8. => North,
|
|
|
|
h if h > 5. * PI / 8. && h <= 7. * PI / 8. => NorthWest,
|
|
|
|
h if h > 7. * PI / 8. || h <= -7. * PI / 8. => East,
|
|
|
|
h if h > -7. * PI / 8. && h <= -5. * PI / 8. => SouthEast,
|
|
|
|
h if h > -5. * PI / 8. && h <= -3. * PI / 8. => South,
|
|
|
|
h if h > -3. * PI / 8. && h <= -PI / 8. => SouthWest,
|
|
|
|
_ => West,
|
|
|
|
})
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Converting from strings into directions doesn't make sense.
|
|
|
|
#[allow(clippy::from_over_into)]
|
|
|
|
impl Into<String> for MovementDirection {
|
|
|
|
fn into(self) -> String {
|
2024-10-06 22:17:48 +00:00
|
|
|
use CompassOctant::*;
|
|
|
|
match self.0 {
|
|
|
|
North => "north",
|
|
|
|
NorthEast => "northeast",
|
|
|
|
East => "east",
|
|
|
|
SouthEast => "southeast",
|
|
|
|
South => "south",
|
|
|
|
SouthWest => "southwest",
|
|
|
|
West => "west",
|
|
|
|
NorthWest => "northwest",
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
2024-10-06 22:17:48 +00:00
|
|
|
.into()
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for MovementDirection {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
let str: String = (*self).into();
|
|
|
|
write!(f, "{}", str)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-06 22:17:48 +00:00
|
|
|
#[derive(Component, Clone, Copy, Debug, Eq, PartialEq, Deref, DerefMut, Reflect)]
|
2022-12-19 20:08:31 +00:00
|
|
|
#[reflect(Component)]
|
2024-10-06 22:17:48 +00:00
|
|
|
pub struct CardinalDirection(pub CompassQuadrant);
|
|
|
|
|
|
|
|
impl Default for CardinalDirection {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self(CompassQuadrant::East)
|
|
|
|
}
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
|
2024-10-06 22:17:48 +00:00
|
|
|
impl From<Rot2> for CardinalDirection {
|
|
|
|
fn from(rot: Rot2) -> Self {
|
|
|
|
use CompassQuadrant::*;
|
|
|
|
CardinalDirection(match rot.as_radians() {
|
|
|
|
h if h > -PI / 4. && h <= PI / 4. => East,
|
|
|
|
h if h > PI / 4. && h <= 3. * PI / 4. => North,
|
|
|
|
h if h > 3. * PI / 4. || h <= -3. * PI / 4. => West,
|
|
|
|
_ => South,
|
|
|
|
})
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-06 22:17:48 +00:00
|
|
|
impl From<&CardinalDirection> for Rot2 {
|
2022-02-11 14:44:41 +00:00
|
|
|
fn from(direction: &CardinalDirection) -> Self {
|
2024-10-06 22:17:48 +00:00
|
|
|
use CompassQuadrant::*;
|
|
|
|
match direction.0 {
|
|
|
|
North => Rot2::radians(PI / 2.),
|
|
|
|
East => Rot2::radians(0.),
|
|
|
|
South => Rot2::radians(-PI / 2.),
|
|
|
|
West => Rot2::radians(PI),
|
2022-02-11 14:44:41 +00:00
|
|
|
}
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Converting from strings into directions doesn't make sense.
|
|
|
|
#[allow(clippy::from_over_into)]
|
|
|
|
impl Into<String> for CardinalDirection {
|
|
|
|
fn into(self) -> String {
|
2024-10-06 22:17:48 +00:00
|
|
|
use CompassQuadrant::*;
|
|
|
|
match self.0 {
|
2021-05-13 17:25:45 +00:00
|
|
|
North => "north".to_string(),
|
|
|
|
East => "east".to_string(),
|
|
|
|
South => "south".to_string(),
|
|
|
|
West => "west".to_string(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for CardinalDirection {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
let str: String = (*self).into();
|
|
|
|
write!(f, "{}", str)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-29 18:29:45 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
|
|
|
pub enum RelativeDirectionMode {
|
|
|
|
ClockFacing,
|
|
|
|
Directional,
|
|
|
|
}
|
|
|
|
|
|
|
|
static RELATIVE_DIRECTION_MODE: Lazy<RwLock<RelativeDirectionMode>> = Lazy::new(|| {
|
|
|
|
let v = RelativeDirectionMode::Directional;
|
|
|
|
RwLock::new(v)
|
|
|
|
});
|
|
|
|
|
2022-07-19 16:24:45 +00:00
|
|
|
static PHYSICS_SCALE: Lazy<RwLock<f32>> = Lazy::new(|| RwLock::new(1.));
|
|
|
|
|
2021-05-13 17:25:45 +00:00
|
|
|
pub trait PointLike {
|
|
|
|
fn x(&self) -> f32;
|
|
|
|
|
|
|
|
fn y(&self) -> f32;
|
|
|
|
|
|
|
|
fn x_i32(&self) -> i32 {
|
2023-03-28 13:49:46 +00:00
|
|
|
self.x().trunc() as i32
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn y_i32(&self) -> i32 {
|
2023-03-28 13:49:46 +00:00
|
|
|
self.y().trunc() as i32
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn x_usize(&self) -> usize {
|
2022-05-18 15:28:19 +00:00
|
|
|
self.x().trunc() as usize
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn y_usize(&self) -> usize {
|
2022-05-18 15:28:19 +00:00
|
|
|
self.y().trunc() as usize
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
2021-05-24 19:02:22 +00:00
|
|
|
|
|
|
|
fn f32(&self) -> (f32, f32) {
|
|
|
|
(self.x(), self.y())
|
|
|
|
}
|
|
|
|
|
2021-05-13 17:25:45 +00:00
|
|
|
fn i32(&self) -> (i32, i32) {
|
|
|
|
(self.x_i32(), self.y_i32())
|
|
|
|
}
|
|
|
|
|
2023-03-28 13:49:46 +00:00
|
|
|
fn trunc(&self) -> (f32, f32) {
|
|
|
|
(self.x().trunc(), self.y().trunc())
|
2021-09-27 18:18:45 +00:00
|
|
|
}
|
2022-05-18 15:28:19 +00:00
|
|
|
|
2021-05-13 17:25:45 +00:00
|
|
|
fn to_index(&self, width: usize) -> usize {
|
2023-03-28 13:49:46 +00:00
|
|
|
(self.y_usize() * width) + self.x_usize()
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn distance_squared(&self, other: &dyn PointLike) -> f32 {
|
|
|
|
let x1 = FloatOrd(self.x());
|
|
|
|
let y1 = FloatOrd(self.y());
|
|
|
|
let x2 = FloatOrd(other.x());
|
|
|
|
let y2 = FloatOrd(other.y());
|
|
|
|
let dx = max(x1, x2).0 - min(x1, x2).0;
|
|
|
|
let dy = max(y1, y2).0 - min(y1, y2).0;
|
|
|
|
(dx * dx) + (dy * dy)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn distance(&self, other: &dyn PointLike) -> f32 {
|
|
|
|
self.distance_squared(other).sqrt()
|
|
|
|
}
|
|
|
|
|
2024-10-06 22:17:48 +00:00
|
|
|
fn bearing(&self, other: &dyn PointLike) -> Rot2 {
|
2021-05-13 17:25:45 +00:00
|
|
|
let y = other.y() - self.y();
|
|
|
|
let x = other.x() - self.x();
|
2024-10-06 22:17:48 +00:00
|
|
|
Rot2::radians(y.atan2(x))
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn direction(&self, other: &dyn PointLike) -> MovementDirection {
|
2021-05-16 22:24:26 +00:00
|
|
|
self.bearing(other).into()
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
|
2024-10-06 22:17:48 +00:00
|
|
|
fn direction_and_distance(&self, other: &dyn PointLike, yaw: Option<Rot2>) -> String {
|
2021-05-13 17:25:45 +00:00
|
|
|
let mut tokens: Vec<String> = vec![];
|
|
|
|
let distance = self.distance(other).round() as i32;
|
|
|
|
if distance > 0 {
|
|
|
|
let tile_or_tiles = if distance == 1 { "tile" } else { "tiles" };
|
2021-05-16 22:24:26 +00:00
|
|
|
let direction: String = if let Some(yaw) = yaw {
|
2024-10-06 22:17:48 +00:00
|
|
|
let yaw = yaw.as_radians();
|
|
|
|
let bearing = self.bearing(other).as_radians();
|
|
|
|
let rot = Rot2::radians(bearing - yaw);
|
|
|
|
relative_desc(&rot)
|
2021-05-16 22:24:26 +00:00
|
|
|
} else {
|
|
|
|
self.direction(other).into()
|
|
|
|
};
|
2022-01-19 22:38:32 +00:00
|
|
|
tokens.push(format!("{direction} {distance} {tile_or_tiles}"));
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
tokens.join(" ")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-01 16:01:51 +00:00
|
|
|
impl PointLike for Transform {
|
|
|
|
fn x(&self) -> f32 {
|
|
|
|
self.translation.x
|
|
|
|
}
|
|
|
|
|
|
|
|
fn y(&self) -> f32 {
|
|
|
|
self.translation.y
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-10 18:56:49 +00:00
|
|
|
impl PointLike for &Transform {
|
|
|
|
fn x(&self) -> f32 {
|
|
|
|
self.translation.x
|
|
|
|
}
|
|
|
|
|
|
|
|
fn y(&self) -> f32 {
|
|
|
|
self.translation.y
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-11 18:34:03 +00:00
|
|
|
impl PointLike for GlobalTransform {
|
|
|
|
fn x(&self) -> f32 {
|
2022-08-01 16:38:15 +00:00
|
|
|
self.translation().x
|
2022-05-11 18:34:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn y(&self) -> f32 {
|
2022-08-01 16:38:15 +00:00
|
|
|
self.translation().y
|
2022-05-11 18:34:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-13 15:06:04 +00:00
|
|
|
impl PointLike for &GlobalTransform {
|
|
|
|
fn x(&self) -> f32 {
|
|
|
|
self.translation().x
|
|
|
|
}
|
|
|
|
|
|
|
|
fn y(&self) -> f32 {
|
|
|
|
self.translation().y
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-28 15:04:53 +00:00
|
|
|
impl PointLike for Vec2 {
|
|
|
|
fn x(&self) -> f32 {
|
|
|
|
self.x
|
|
|
|
}
|
|
|
|
|
|
|
|
fn y(&self) -> f32 {
|
|
|
|
self.y
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-13 17:25:45 +00:00
|
|
|
impl PointLike for (i32, i32) {
|
|
|
|
fn x(&self) -> f32 {
|
|
|
|
self.0 as f32
|
|
|
|
}
|
|
|
|
|
|
|
|
fn y(&self) -> f32 {
|
|
|
|
self.1 as f32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PointLike for (f32, f32) {
|
|
|
|
fn x(&self) -> f32 {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
|
|
|
|
fn y(&self) -> f32 {
|
|
|
|
self.1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PointLike for (usize, usize) {
|
|
|
|
fn x(&self) -> f32 {
|
|
|
|
self.0 as f32
|
|
|
|
}
|
|
|
|
|
|
|
|
fn y(&self) -> f32 {
|
|
|
|
self.1 as f32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-18 20:58:27 +00:00
|
|
|
impl PointLike for here_be_dragons::geometry::Point {
|
2021-05-13 17:25:45 +00:00
|
|
|
fn x(&self) -> f32 {
|
|
|
|
self.x as f32
|
|
|
|
}
|
|
|
|
|
|
|
|
fn y(&self) -> f32 {
|
|
|
|
self.y as f32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! impl_pointlike_for_tuple_component {
|
|
|
|
($source:ty) => {
|
|
|
|
impl PointLike for $source {
|
|
|
|
fn x(&self) -> f32 {
|
|
|
|
self.0 .0 as f32
|
|
|
|
}
|
|
|
|
|
|
|
|
fn y(&self) -> f32 {
|
|
|
|
self.0 .1 as f32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<&dyn PointLike> for (i32, i32) {
|
|
|
|
fn from(val: &dyn PointLike) -> Self {
|
2021-05-24 19:02:22 +00:00
|
|
|
val.i32()
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-21 18:56:00 +00:00
|
|
|
pub trait TransformExt {
|
2024-10-06 22:17:48 +00:00
|
|
|
fn yaw(&self) -> Rot2;
|
2022-09-21 18:56:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TransformExt for Transform {
|
2024-10-06 22:17:48 +00:00
|
|
|
fn yaw(&self) -> Rot2 {
|
2022-09-21 18:56:00 +00:00
|
|
|
let forward = self.right();
|
2024-10-06 22:17:48 +00:00
|
|
|
Rot2::radians(forward.y.atan2(forward.x))
|
2022-09-21 18:56:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-19 16:24:45 +00:00
|
|
|
pub trait GlobalTransformExt {
|
2024-10-06 22:17:48 +00:00
|
|
|
fn yaw(&self) -> Rot2;
|
2022-08-22 20:51:07 +00:00
|
|
|
|
|
|
|
fn closest_points(
|
|
|
|
&self,
|
|
|
|
collider: &Collider,
|
|
|
|
other: &GlobalTransform,
|
|
|
|
other_collider: &Collider,
|
|
|
|
) -> ClosestPoints;
|
|
|
|
|
2022-07-19 16:24:45 +00:00
|
|
|
fn collider_direction_and_distance(
|
|
|
|
&self,
|
|
|
|
collider: &Collider,
|
|
|
|
other: &GlobalTransform,
|
|
|
|
other_collider: &Collider,
|
|
|
|
) -> String;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GlobalTransformExt for GlobalTransform {
|
2024-10-06 22:17:48 +00:00
|
|
|
fn yaw(&self) -> Rot2 {
|
2022-08-02 21:49:27 +00:00
|
|
|
let forward = self.right();
|
2024-10-06 22:17:48 +00:00
|
|
|
Rot2::radians(forward.y.atan2(forward.x))
|
2022-07-19 16:24:45 +00:00
|
|
|
}
|
|
|
|
|
2022-08-22 20:51:07 +00:00
|
|
|
fn closest_points(
|
|
|
|
&self,
|
|
|
|
collider: &Collider,
|
|
|
|
other: &GlobalTransform,
|
|
|
|
other_collider: &Collider,
|
|
|
|
) -> ClosestPoints {
|
|
|
|
let scale = PHYSICS_SCALE.read().unwrap();
|
|
|
|
let pos1 = Isometry::new(
|
|
|
|
(self.translation() / *scale).xy().into(),
|
2024-10-06 22:17:48 +00:00
|
|
|
self.yaw().as_radians(),
|
2022-08-22 20:51:07 +00:00
|
|
|
);
|
|
|
|
let pos2 = Isometry::new(
|
|
|
|
(other.translation() / *scale).xy().into(),
|
2024-10-06 22:17:48 +00:00
|
|
|
other.yaw().as_radians(),
|
2022-08-22 20:51:07 +00:00
|
|
|
);
|
|
|
|
closest_points(&pos1, &*collider.raw, &pos2, &*other_collider.raw, f32::MAX).unwrap()
|
|
|
|
}
|
|
|
|
|
2022-07-19 16:24:45 +00:00
|
|
|
fn collider_direction_and_distance(
|
|
|
|
&self,
|
|
|
|
collider: &Collider,
|
|
|
|
other: &GlobalTransform,
|
|
|
|
other_collider: &Collider,
|
|
|
|
) -> String {
|
|
|
|
let scale = PHYSICS_SCALE.read().unwrap();
|
|
|
|
let pos1 = Isometry::new(
|
2022-08-01 16:38:15 +00:00
|
|
|
(self.translation() / *scale).xy().into(),
|
2024-10-06 22:17:48 +00:00
|
|
|
self.yaw().as_radians(),
|
2022-07-19 16:24:45 +00:00
|
|
|
);
|
|
|
|
let pos2 = Isometry::new(
|
2022-08-01 16:38:15 +00:00
|
|
|
(other.translation() / *scale).xy().into(),
|
2024-10-06 22:17:48 +00:00
|
|
|
other.yaw().as_radians(),
|
2022-07-19 16:24:45 +00:00
|
|
|
);
|
2022-08-22 20:51:07 +00:00
|
|
|
let closest = self.closest_points(collider, other, other_collider);
|
2022-08-02 22:17:08 +00:00
|
|
|
let distance = distance(&pos1, &*collider.raw, &pos2, &*other_collider.raw).unwrap() as u32;
|
2022-07-19 16:24:45 +00:00
|
|
|
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);
|
2024-10-06 22:17:48 +00:00
|
|
|
let bearing = p1.bearing(&p2).as_radians();
|
|
|
|
let yaw = self.yaw().as_radians();
|
|
|
|
let rot = Rot2::radians(bearing - yaw);
|
|
|
|
let direction = relative_desc(&rot);
|
2022-07-19 16:24:45 +00:00
|
|
|
format!("{direction} {distance} {tile_or_tiles}")
|
|
|
|
} else {
|
|
|
|
format!("{} {}", distance, tile_or_tiles)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
format!("{} {}", distance, tile_or_tiles)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-19 16:56:41 +00:00
|
|
|
#[derive(Component, Copy, Clone, Debug, Deref, DerefMut, PartialEq)]
|
2022-12-19 20:08:31 +00:00
|
|
|
pub struct Area(pub Aabb);
|
2022-07-19 16:56:41 +00:00
|
|
|
|
2022-01-10 19:50:52 +00:00
|
|
|
#[derive(Component, Clone, Copy, Debug, Default, Reflect)]
|
2021-05-13 17:25:45 +00:00
|
|
|
#[reflect(Component)]
|
|
|
|
pub struct Player;
|
|
|
|
|
2021-06-02 00:38:33 +00:00
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub struct Pool<T> {
|
|
|
|
pub value: T,
|
|
|
|
pub max: T,
|
|
|
|
}
|
|
|
|
|
2021-10-05 14:16:44 +00:00
|
|
|
impl<T> Default for Pool<T>
|
|
|
|
where
|
|
|
|
T: Default,
|
|
|
|
{
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
value: Default::default(),
|
|
|
|
max: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-02 16:40:40 +00:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct RandomTable<T>(Vec<T>)
|
|
|
|
where
|
|
|
|
T: Clone;
|
|
|
|
|
|
|
|
impl<T> RandomTable<T>
|
|
|
|
where
|
|
|
|
T: Clone,
|
|
|
|
{
|
2021-08-03 13:57:40 +00:00
|
|
|
pub fn add(&mut self, value: T, weight: i32) -> &mut Self {
|
|
|
|
if weight > 0 {
|
|
|
|
for _ in 0..weight {
|
|
|
|
self.0.push(value.clone());
|
|
|
|
}
|
2021-06-02 16:40:40 +00:00
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Default for RandomTable<T>
|
|
|
|
where
|
|
|
|
T: Clone,
|
|
|
|
{
|
|
|
|
fn default() -> Self {
|
|
|
|
Self(vec![])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Iterator for RandomTable<T>
|
|
|
|
where
|
|
|
|
T: Clone,
|
|
|
|
{
|
|
|
|
type Item = T;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
let mut rng = thread_rng();
|
|
|
|
self.0.shuffle(&mut rng);
|
2024-03-14 18:37:46 +00:00
|
|
|
self.0.first().cloned()
|
2021-06-02 16:40:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-06 16:07:59 +00:00
|
|
|
fn setup(core_config: Res<CoreConfig>) {
|
2022-07-19 16:24:45 +00:00
|
|
|
let mut scale = PHYSICS_SCALE.write().unwrap();
|
|
|
|
*scale = core_config.pixels_per_unit as f32;
|
2021-11-29 18:29:45 +00:00
|
|
|
let mut mode = RELATIVE_DIRECTION_MODE.write().unwrap();
|
|
|
|
*mode = core_config.relative_direction_mode;
|
2021-06-02 19:47:49 +00:00
|
|
|
}
|
|
|
|
|
2022-12-19 20:08:31 +00:00
|
|
|
#[derive(Resource, Clone, Copy, Debug)]
|
2021-05-13 17:25:45 +00:00
|
|
|
pub struct CoreConfig {
|
2021-11-29 18:29:45 +00:00
|
|
|
pub relative_direction_mode: RelativeDirectionMode,
|
2021-05-13 17:25:45 +00:00
|
|
|
pub pixels_per_unit: u8,
|
|
|
|
}
|
|
|
|
|
2021-11-29 18:29:45 +00:00
|
|
|
fn sync_config(config: Res<CoreConfig>) {
|
|
|
|
if config.is_changed() {
|
|
|
|
let mut mode = RELATIVE_DIRECTION_MODE.write().unwrap();
|
|
|
|
*mode = config.relative_direction_mode;
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-28 16:57:37 +00:00
|
|
|
pub struct CorePlugin {
|
2022-12-20 15:15:09 +00:00
|
|
|
pub relative_direction_mode: RelativeDirectionMode,
|
|
|
|
pub pixels_per_unit: u8,
|
|
|
|
}
|
2022-05-06 16:07:59 +00:00
|
|
|
|
2023-03-28 16:57:37 +00:00
|
|
|
impl Default for CorePlugin {
|
2022-05-06 16:07:59 +00:00
|
|
|
fn default() -> Self {
|
2022-12-20 15:15:09 +00:00
|
|
|
Self {
|
|
|
|
relative_direction_mode: RelativeDirectionMode::Directional,
|
|
|
|
pixels_per_unit: 1,
|
|
|
|
}
|
2022-05-06 16:07:59 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-13 17:25:45 +00:00
|
|
|
|
2023-03-28 16:57:37 +00:00
|
|
|
impl Plugin for CorePlugin {
|
2022-01-10 19:50:52 +00:00
|
|
|
fn build(&self, app: &mut App) {
|
2022-12-20 15:15:09 +00:00
|
|
|
let config = CoreConfig {
|
|
|
|
relative_direction_mode: self.relative_direction_mode,
|
|
|
|
pixels_per_unit: self.pixels_per_unit,
|
|
|
|
};
|
|
|
|
app.insert_resource(config)
|
|
|
|
.register_type::<CardinalDirection>()
|
2023-09-08 21:12:35 +00:00
|
|
|
.add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(
|
2022-12-19 20:08:31 +00:00
|
|
|
config.pixels_per_unit as f32,
|
|
|
|
))
|
2023-09-08 21:12:35 +00:00
|
|
|
.add_systems(Startup, setup)
|
|
|
|
.add_systems(Update, sync_config);
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-28 16:57:37 +00:00
|
|
|
pub struct CorePlugins;
|
2021-05-13 17:25:45 +00:00
|
|
|
|
2023-03-28 16:57:37 +00:00
|
|
|
impl PluginGroup for CorePlugins {
|
2022-12-19 20:08:31 +00:00
|
|
|
fn build(self) -> PluginGroupBuilder {
|
|
|
|
PluginGroupBuilder::start::<Self>()
|
2021-05-13 17:25:45 +00:00
|
|
|
.add(crate::bevy_tts::TtsPlugin)
|
2022-12-19 20:08:31 +00:00
|
|
|
.add(crate::bevy_synthizer::SynthizerPlugin::default())
|
2024-10-06 15:42:25 +00:00
|
|
|
.add(crate::navigation::NavigationPlugin::default())
|
2023-03-28 16:57:37 +00:00
|
|
|
.add(CorePlugin::default())
|
2021-05-13 17:25:45 +00:00
|
|
|
}
|
|
|
|
}
|