use bevy::math::bounding::{Aabb3d, RayCast3d};
use bevy::math::Ray3d;
use bevy::prelude::Component;
use glam::Vec3;
use crate::position::TilePosition;
use crate::prelude::perspective::Perspective;
#[derive(Debug, Clone)]
pub struct Traversal {
pub ray_cast: RayCast3d,
pub target_area: Vec<TilePosition>,
}
impl Traversal {
pub fn new(ray_cast: RayCast3d, target_area: Vec<TilePosition>) -> Self {
Traversal {
ray_cast,
target_area,
}
}
pub fn get_intersections(self) -> Vec<TilePosition> {
self.get_intersections_with(|pos| Aabb3d::from(*pos))
}
pub fn get_intersections_with(
self,
aabb_transformer: impl Fn(&TilePosition) -> Aabb3d,
) -> Vec<TilePosition> {
self.target_area
.into_iter()
.filter_map(|pos| {
self.ray_cast
.aabb_intersection_at(&aabb_transformer(&pos))?;
Some(pos)
})
.collect()
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Component)]
pub struct RadialArea {
pub range: u8,
pub center_pos: TilePosition,
pub angle_step: usize,
pub angle_range: (u16, u16),
}
impl Default for RadialArea {
fn default() -> Self {
Self {
range: 1,
center_pos: TilePosition::new(0, 0, 0),
angle_step: 10,
angle_range: (315, 405),
}
}
}
impl RadialArea {
pub fn new() -> Self {
Self::default()
}
pub fn get_center_pos(&self) -> TilePosition {
self.center_pos
}
pub fn circle() -> Self {
Self::default().with_angle_range((45, 405))
}
pub fn sector(start_angle: u16, end_angle: u16) -> Self {
Self::default().with_angle_range((start_angle, end_angle))
}
pub fn with_range(self, range: u8) -> Self {
Self { range, ..self }
}
pub fn with_center_pos(self, center_pos: TilePosition) -> Self {
Self { center_pos, ..self }
}
pub fn with_angle_step(self, angle_step: usize) -> Self {
Self { angle_step, ..self }
}
pub fn with_angle_range(self, angle_range: (u16, u16)) -> Self {
let (start_angle, end_angle) = angle_range;
Self {
angle_range: if start_angle < end_angle {
(start_angle, end_angle)
} else {
(end_angle, start_angle)
},
..self
}
}
}
impl From<RadialArea> for Perspective {
fn from(radial_area: RadialArea) -> Self {
let RadialArea {
range,
center_pos,
angle_step,
angle_range: (start_angle, end_angle),
} = radial_area;
if range == 0 {
return Perspective::default();
}
let center_pos_vec3 = Vec3::new(
center_pos.x as f32,
center_pos.y as f32,
center_pos.z as f32,
);
Perspective::new(
center_pos
.tiles_on_arc_circumference(range, start_angle, end_angle, angle_step)
.into_iter()
.map(|arc_tile| {
let ray_cast = RayCast3d::from_ray(
Ray3d::new(center_pos_vec3, (arc_tile.0 - center_pos.0).as_vec3()),
range as f32,
);
Traversal::new(ray_cast, center_pos.bresenhams_line(arc_tile))
})
.collect::<Vec<_>>(),
)
}
}