use super::systems::sdf_box;
use bevy::prelude::*;
#[derive(Component, Debug, Clone)]
pub enum PhysicsCollider {
Circle { radius: f32 },
Box { half_size: Vec2 },
}
impl PhysicsCollider {
pub fn sdf_distance(&self, point: Vec2, center: Vec2) -> f32 {
let relative_pos = point - center;
match self {
PhysicsCollider::Circle { radius } => relative_pos.length() - radius,
PhysicsCollider::Box { half_size } => sdf_box(relative_pos, *half_size),
}
}
}
#[derive(Component, Debug, Clone)]
pub enum TriggerCollider {
Circle { radius: f32 },
Box { half_size: Vec2 },
}
impl TriggerCollider {
pub fn contains_point(&self, point: Vec2, center: Vec2) -> bool {
let relative_pos = point - center;
match self {
TriggerCollider::Circle { radius } => relative_pos.length() <= *radius,
TriggerCollider::Box { half_size } => {
relative_pos.x.abs() <= half_size.x && relative_pos.y.abs() <= half_size.y
}
}
}
}
#[derive(Component, Debug, Clone)]
pub struct BattleBoxBoundary {
pub half_size: Vec2,
pub center: Vec2,
}
impl BattleBoxBoundary {
pub fn from_ui_box(width: f32, height: f32, center: Vec2) -> Self {
Self {
half_size: Vec2::new(width / 2.0, height / 2.0),
center,
}
}
pub fn sdf_distance(&self, point: Vec2) -> f32 {
let relative_pos = point - self.center;
sdf_box(relative_pos, self.half_size)
}
pub fn clamp_position(&self, position: Vec2) -> Vec2 {
Vec2::new(
position.x.clamp(
self.center.x - self.half_size.x,
self.center.x + self.half_size.x,
),
position.y.clamp(
self.center.y - self.half_size.y,
self.center.y + self.half_size.y,
),
)
}
pub fn constrain_with_collider(&self, position: Vec2, collider: &PhysicsCollider) -> Vec2 {
let effective_half_size = match collider {
PhysicsCollider::Circle { radius } => self.half_size - Vec2::splat(*radius),
PhysicsCollider::Box { half_size } => self.half_size - *half_size,
};
let adjusted_boundary = BattleBoxBoundary {
half_size: effective_half_size,
center: self.center,
};
let distance = adjusted_boundary.sdf_distance(position);
if distance < 0.0 {
return position;
}
let relative_pos = position - self.center;
let pen_x = relative_pos.x.abs() - effective_half_size.x;
let pen_y = relative_pos.y.abs() - effective_half_size.y;
let mut result = position;
if pen_x > 0.0 {
let sign = relative_pos.x.signum();
result.x = self.center.x + sign * effective_half_size.x;
}
if pen_y > 0.0 {
let sign = relative_pos.y.signum();
result.y = self.center.y + sign * effective_half_size.y;
}
result
}
#[allow(dead_code)]
fn compute_gradient(&self, position: Vec2, epsilon: f32) -> Vec2 {
let dx = self.sdf_distance(position + Vec2::new(epsilon, 0.0))
- self.sdf_distance(position - Vec2::new(epsilon, 0.0));
let dy = self.sdf_distance(position + Vec2::new(0.0, epsilon))
- self.sdf_distance(position - Vec2::new(0.0, epsilon));
Vec2::new(dx, dy) / (2.0 * epsilon)
}
}