use ecs::Component; use crate::mesh::Mesh; use crate::vector::Vec3; pub trait Collider { fn intersects(&self, other: &Other) -> bool; } #[derive(Debug, Default, Clone, Component)] #[non_exhaustive] pub struct BoxCollider { pub min: Vec3, pub max: Vec3, } impl BoxCollider { pub fn for_mesh(mesh: &Mesh) -> Self { let furthest_dir_points = mesh.find_furthest_vertex_positions(); Self { min: Vec3 { x: furthest_dir_points.left.x, y: furthest_dir_points.down.y, z: furthest_dir_points.back.z, }, max: Vec3 { x: furthest_dir_points.right.x, y: furthest_dir_points.up.y, z: furthest_dir_points.front.z, }, } } pub fn offset(self, offset: Vec3) -> Self { Self { min: self.min + offset, max: self.max + offset, } } } impl Collider for BoxCollider { fn intersects(&self, other: &BoxCollider) -> bool { self.min.x <= other.max.x && self.max.x >= other.min.x && self.min.y <= other.max.y && self.max.y >= other.min.y && self.min.z <= other.max.z && self.max.z >= other.min.z } } impl Collider for BoxCollider { fn intersects(&self, other: &SphereCollider) -> bool { other.intersects(self) } } impl Collider> for BoxCollider { fn intersects(&self, other: &Vec3) -> bool { other.x >= self.min.x && other.y >= self.min.y && other.z >= self.min.z && other.x <= self.max.x && other.y <= self.max.y && other.z <= self.max.z } } #[derive(Debug, Default, Clone, Component)] pub struct SphereCollider { pub center: Vec3, pub radius: f32, } impl SphereCollider { pub fn offset(self, offset: Vec3) -> Self { Self { center: self.center + offset, radius: self.radius, } } } impl Collider for SphereCollider { fn intersects(&self, other: &SphereCollider) -> bool { (&self.center - &other.center).length() <= self.radius + other.radius } } impl Collider for SphereCollider { fn intersects(&self, other: &BoxCollider) -> bool { let mut min_distance = 0.0; if self.center.x < other.min.x { min_distance += (self.center.x - other.min.x).powf(2.0); } else if self.center.x > other.max.x { min_distance += (self.center.x - other.max.x).powf(2.0); } if self.center.y < other.min.y { min_distance += (self.center.y - other.min.y).powf(2.0); } else if self.center.y > other.max.y { min_distance += (self.center.y - other.max.y).powf(2.0); } if self.center.z < other.min.z { min_distance += (self.center.z - other.min.z).powf(2.0); } else if self.center.z > other.max.z { min_distance += (self.center.z - other.max.z).powf(2.0); } min_distance <= self.radius.powf(2.0) } } impl Collider> for SphereCollider { fn intersects(&self, other: &Vec3) -> bool { (&self.center - other).length() <= self.radius } }