use crate::{shape::CollisionRotatedRect, CollisionCircle, CollisionRect};
use bevy_ecs::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Relation {
Disjoint,
Overlap,
Contain,
Contained,
}
pub trait Collision<S> {
fn detect(&self, obj: &S) -> Relation;
}
pub trait DynCollision:
Collision<CollisionRect>
+ Collision<CollisionRotatedRect>
+ Collision<CollisionCircle>
+ Send
+ Sync
{
}
impl<T> DynCollision for T where
T: Collision<CollisionRect>
+ Collision<CollisionRotatedRect>
+ Collision<CollisionCircle>
+ Send
+ Sync
{
}
#[allow(missing_docs)]
pub trait AsDynCollision {
fn as_dyn_collision(&self) -> Box<dyn DynCollision>;
}
impl<const D: usize> AsDynCollision for CollisionRect<D> {
fn as_dyn_collision(&self) -> Box<dyn DynCollision> {
let this = CollisionRect::from(self);
Box::new(this)
}
}
impl<const D: usize> AsDynCollision for CollisionRotatedRect<D> {
fn as_dyn_collision(&self) -> Box<dyn DynCollision> {
let this = CollisionRotatedRect::from(self);
Box::new(this)
}
}
impl<const D: usize> AsDynCollision for CollisionCircle<D> {
fn as_dyn_collision(&self) -> Box<dyn DynCollision> {
let this = CollisionCircle::from(self);
Box::new(this)
}
}
pub trait UpdateCollision<C>
where
C: Component,
{
fn update() -> impl FnOnce(Mut<Self>, &C);
}
pub trait Disassemble {
fn disassemble(
&self,
) -> (
Vec<&CollisionRect>,
Vec<&CollisionRotatedRect>,
Vec<&CollisionCircle>,
);
}
pub trait CollisionQuery {
fn query(&self, obj: &dyn DynCollision) -> Relation;
}
impl<S> CollisionQuery for S
where
S: Disassemble,
{
fn query(&self, obj: &dyn DynCollision) -> Relation {
let (rects, rotated_rects, circles) = self.disassemble();
let mut relation = Relation::Contain;
for rect in rects {
match obj.detect(rect) {
Relation::Contain => return Relation::Contained,
Relation::Contained if relation == Relation::Contain => {}
Relation::Contained | Relation::Overlap => return Relation::Overlap,
Relation::Disjoint => relation = Relation::Disjoint,
}
}
for r_rect in rotated_rects {
match obj.detect(r_rect) {
Relation::Contain => return Relation::Contained,
Relation::Contained if relation == Relation::Contain => {}
Relation::Contained | Relation::Overlap => return Relation::Overlap,
Relation::Disjoint => relation = Relation::Disjoint,
}
}
for circle in circles {
match obj.detect(circle) {
Relation::Contain => return Relation::Contained,
Relation::Contained if relation == Relation::Contain => {}
Relation::Contained | Relation::Overlap => return Relation::Overlap,
Relation::Disjoint => relation = Relation::Disjoint,
}
}
relation
}
}
impl<T> Disassemble for [T]
where
T: Disassemble,
{
fn disassemble(
&self,
) -> (
Vec<&CollisionRect>,
Vec<&CollisionRotatedRect>,
Vec<&CollisionCircle>,
) {
let mut rects = vec![];
let mut rotated_rects = vec![];
let mut circles = vec![];
for t in self {
let (r, rr, c) = t.disassemble();
rects.extend(r);
rotated_rects.extend(rr);
circles.extend(c);
}
(rects, rotated_rects, circles)
}
}
macro_rules! impl_disassemable {
($($i: literal),+) => {
paste::paste! {
impl<$([<S $i>]),+> Disassemble for ($([<S $i>]),+,)
where
$([<S $i>]: Disassemble,)+
{
fn disassemble(
&self,
) -> (
Vec<&CollisionRect>,
Vec<&CollisionRotatedRect>,
Vec<&CollisionCircle>,
) {
let mut rects = vec![];
let mut rotated_rects = vec![];
let mut circles = vec![];
$(
let (r, rr, c) = self.$i.disassemble();
rects.extend(r);
rotated_rects.extend(rr);
circles.extend(c);
)+
(rects, rotated_rects, circles)
}
}
}
};
}
impl_disassemable!(0);
impl_disassemable!(0, 1);
impl_disassemable!(0, 1, 2);
impl_disassemable!(0, 1, 2, 3);
impl_disassemable!(0, 1, 2, 3, 4);
impl_disassemable!(0, 1, 2, 3, 4, 5);
impl_disassemable!(0, 1, 2, 3, 4, 5, 6);
impl_disassemable!(0, 1, 2, 3, 4, 5, 6, 7);
impl_disassemable!(0, 1, 2, 3, 4, 5, 6, 7, 8);