engine/entity_manager/src/hitbox.rs

158 lines
3.2 KiB
Rust
Raw Normal View History

2024-08-23 11:22:09 +00:00
use anyhow::Result;
use engine::prelude::*;
use cgmath::Vector2;
pub enum CollisionEventType {
Block,
Ignore,
}
pub type HitCallback =
2025-02-27 13:14:29 +00:00
dyn FnMut(&mut World, Entity, Entity) -> Result<CollisionEventType> + Send + Sync;
2024-08-23 11:22:09 +00:00
// HitBox is basically a cylinder
pub struct HitBox {
pub radius: f32,
height: f32,
hit_event: Option<Box<HitCallback>>,
}
impl HitBox {
pub fn from_bb(bounding_box: &BoundingBox) -> Self {
Self {
radius: Self::calculate_radius(bounding_box),
height: bounding_box.max[2] - bounding_box.min[2],
hit_event: None,
}
}
pub fn new(radius: f32, height: f32) -> Self {
Self {
radius,
height,
hit_event: None,
}
}
pub fn forced(bounding_box: &BoundingBox, radius: f32, height: f32) -> Self {
Self {
radius: if radius == 0.0 {
Self::calculate_radius(bounding_box)
} else {
radius
},
height: if height == 0.0 {
bounding_box.max[2] - bounding_box.min[2]
} else {
height
},
hit_event: None,
}
}
pub fn calculate_radius(bounding_box: &BoundingBox) -> f32 {
// seek the furthest point
let mut radius = 0.0;
let mut tmp = bounding_box.min[0].abs();
if tmp > radius {
radius = tmp;
}
tmp = bounding_box.min[1].abs();
if tmp > radius {
radius = tmp;
}
tmp = bounding_box.max[0].abs();
if tmp > radius {
radius = tmp;
}
tmp = bounding_box.max[0].abs();
if tmp > radius {
radius = tmp;
}
radius
}
pub fn set_event<F>(&mut self, f: F)
where
2025-02-27 13:14:29 +00:00
F: FnMut(&mut World, Entity, Entity) -> Result<CollisionEventType> + Send + Sync + 'static,
2024-08-23 11:22:09 +00:00
{
self.hit_event = Some(Box::new(f));
}
pub fn set_radius(&mut self, radius: f32) {
self.radius = radius;
}
pub fn set_height(&mut self, height: f32) {
self.height = height;
}
pub fn height(&self) -> f32 {
self.height
}
pub fn radius(&self) -> f32 {
self.radius
}
pub fn check_collision(
&self,
my_pos: Vector2<f32>,
other_radius: f32,
other_pos: Vector2<f32>,
) -> bool {
let d = other_pos - my_pos;
let radii = other_radius + self.radius;
((d.x * d.x) + (d.y * d.y)) <= (radii * radii)
}
pub fn collision(
&mut self,
2025-02-27 13:14:29 +00:00
world: &mut World,
2024-08-23 11:22:09 +00:00
me: Entity,
collider: Entity,
) -> Result<CollisionEventType> {
match &mut self.hit_event {
2025-02-27 13:14:29 +00:00
Some(hit_event) => hit_event(world, me, collider),
2024-08-23 11:22:09 +00:00
None => Ok(CollisionEventType::Ignore),
}
}
}
impl EntityComponent for HitBox {
fn name(&self) -> &str {
Self::debug_name()
}
}
impl ComponentDebug for HitBox {
fn debug_name() -> &'static str {
"HitBox"
}
}
impl Clone for HitBox {
fn clone(&self) -> Self {
Self {
radius: self.radius.clone(),
height: self.height.clone(),
hit_event: None,
}
}
}