use bevy::prelude::{Component, Mut};
use paste::paste;
use crate::{shape::CollisionRotatedRect, CollisionCircle, CollisionRect};
#[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
{
}
pub trait UpdateCollision<C>
where
C: Component,
{
fn update() -> impl FnOnce(Mut<Self>, &C);
}
pub trait CollisionQuery {
fn disassemble(
&self,
) -> (
Vec<&CollisionRect>,
Vec<&CollisionRotatedRect>,
Vec<&CollisionCircle>,
);
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> CollisionQuery for [T]
where
T: CollisionQuery,
{
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_collision_query {
($($i: literal),+) => {
paste! {
impl<$([<S $i>]),+> CollisionQuery for ($([<S $i>]),+,)
where
$([<S $i>]: CollisionQuery,)+
{
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_collision_query!(0);
impl_collision_query!(0, 1);
impl_collision_query!(0, 1, 2);
impl_collision_query!(0, 1, 2, 3);
impl_collision_query!(0, 1, 2, 3, 4);
impl_collision_query!(0, 1, 2, 3, 4, 5);
impl_collision_query!(0, 1, 2, 3, 4, 5, 6);
impl_collision_query!(0, 1, 2, 3, 4, 5, 6, 7);
impl_collision_query!(0, 1, 2, 3, 4, 5, 6, 7, 8);