use de_objects::ObjectCollider;
use parry3d::{
bounding_volume::{Aabb, BoundingVolume},
math::Isometry,
query::{Ray, RayCast},
};
pub trait ColliderWithCache {
fn world_aabb(&self) -> &Aabb;
fn position(&self) -> &Isometry<f32>;
fn inner(&self) -> &ObjectCollider;
}
pub struct LocalCollider {
object_collider: ObjectCollider,
position: Isometry<f32>,
local_aabb: Aabb,
world_aabb: Aabb,
}
impl LocalCollider {
pub fn new(object_collider: ObjectCollider, position: Isometry<f32>) -> Self {
let local_aabb = object_collider.aabb();
let world_aabb = local_aabb.transform_by(&position);
Self {
object_collider,
position,
local_aabb,
world_aabb,
}
}
pub(super) fn update_position(&mut self, position: Isometry<f32>) {
self.world_aabb = self.local_aabb.transform_by(&position);
self.position = position;
}
pub(super) fn cast_ray(&self, ray: &Ray, max_toi: f32) -> Option<f32> {
if self.world_aabb.intersects_local_ray(ray, max_toi) {
self.object_collider.cast_ray(&self.position, ray, max_toi)
} else {
None
}
}
pub(super) fn intersects(&self, rhs: &impl ColliderWithCache) -> bool {
if self.query_aabb(rhs.world_aabb()) {
self.object_collider
.intersects(&self.position, rhs.inner(), rhs.position())
} else {
false
}
}
pub(super) fn query_aabb(&self, aabb: &Aabb) -> bool {
self.world_aabb.intersects(aabb)
}
}
impl ColliderWithCache for LocalCollider {
fn world_aabb(&self) -> &Aabb {
&self.world_aabb
}
fn position(&self) -> &Isometry<f32> {
&self.position
}
fn inner(&self) -> &ObjectCollider {
&self.object_collider
}
}
pub struct QueryCollider<'a> {
inner: &'a ObjectCollider,
position: Isometry<f32>,
world_aabb: Aabb,
}
impl<'a> QueryCollider<'a> {
pub fn new(inner: &'a ObjectCollider, position: Isometry<f32>) -> Self {
let world_aabb = inner.aabb().transform_by(&position);
Self {
inner,
position,
world_aabb,
}
}
}
impl<'a> ColliderWithCache for QueryCollider<'a> {
fn world_aabb(&self) -> &Aabb {
&self.world_aabb
}
fn position(&self) -> &Isometry<f32> {
&self.position
}
fn inner(&self) -> &ObjectCollider {
self.inner
}
}