1use crate::clamp;
4use crate::Point;
5
6pub const POINT_BOUNDING_SIZE: f32 = 0.1;
8
9pub trait Collider {
11 fn get_bounding_box(&self) -> AABB;
13
14 fn get_center(&self) -> Point;
16}
17
18pub trait Collide<T: Collider> {
20 fn collide_with(&self, _other: &T) -> bool;
35}
36
37#[derive(Debug)]
39pub struct AABB {
40 pub min: Point,
42 pub max: Point,
44}
45
46impl Default for AABB {
47 fn default() -> Self {
48 Self {
49 min: Point::new(-0.5, -0.5),
50 max: Point::new(0.5, 0.5),
51 }
52 }
53}
54
55impl AABB {
56 pub fn new_position(x: f32, y: f32) -> Self {
58 Self {
59 min: Point::new(x - 0.5, y - 0.5),
60 max: Point::new(x + 0.5, y + 0.5),
61 }
62 }
63 pub fn new_size(width: f32, height: f32) -> Self {
65 let half: Point = Point::new(width / 2.0, height / 2.0);
66 Self {
67 min: -half,
68 max: half,
69 }
70 }
71 pub fn new_position_and_size(x: f32, y: f32, width: f32, height: f32) -> Self {
73 let position: Point = Point::new(x, y);
74 let half: Point = Point::new(width / 2.0, height / 2.0);
75 Self {
76 min: position - half,
77 max: position + half,
78 }
79 }
80}
81
82#[derive(Debug)]
84pub struct Circle {
85 pub origin: Point,
87 pub radius: f32,
91}
92
93impl Circle {
94 pub fn new_position(x: f32, y: f32) -> Self {
96 Self {
97 origin: Point::new(x, y),
98 radius: 0.5,
99 }
100 }
101 pub fn new_size(radius: f32) -> Self {
103 Self {
104 origin: Point::zeros(),
105 radius,
106 }
107 }
108 pub fn new_position_and_size(x: f32, y: f32, radius: f32) -> Self {
110 Self {
111 origin: Point::new(x, y),
112 radius,
113 }
114 }
115}
116
117impl Collider for Point {
118 fn get_bounding_box(&self) -> AABB {
120 AABB::new_position_and_size(self.x, self.y, POINT_BOUNDING_SIZE, POINT_BOUNDING_SIZE)
121 }
122
123 fn get_center(&self) -> Point {
125 *self
126 }
127}
128
129impl Collider for AABB {
130 fn get_bounding_box(&self) -> AABB {
132 AABB { ..*self }
133 }
134
135 fn get_center(&self) -> Point {
137 self.max - self.min
138 }
139}
140
141impl Collider for Circle {
142 fn get_bounding_box(&self) -> AABB {
143 AABB {
144 min: self.origin - Point::from_element(1.0),
145 max: self.origin + Point::from_element(1.0),
146 }
147 }
148
149 fn get_center(&self) -> Point {
150 self.origin
151 }
152}
153
154impl Collide<Point> for Point {
156 fn collide_with(&self, _other: &Point) -> bool {
157 self == _other
158 }
159}
160
161impl Collide<AABB> for Point {
163 fn collide_with(&self, _other: &AABB) -> bool {
164 _other.collide_with(self)
165 }
166}
167
168impl Collide<Circle> for Point {
170 fn collide_with(&self, _other: &Circle) -> bool {
171 _other.collide_with(self)
172 }
173}
174
175impl Collide<AABB> for AABB {
177 fn collide_with(&self, _other: &AABB) -> bool {
178 self.min.x < _other.max.x
179 && _other.min.x < self.max.x
180 && self.min.y < _other.max.y
181 && _other.min.y < self.max.y
182 }
183}
184
185impl Collide<Point> for AABB {
187 fn collide_with(&self, _other: &Point) -> bool {
188 self.min.x < _other.x
189 && _other.x < self.max.x
190 && self.min.y < _other.y
191 && _other.y < self.max.y
192 }
193}
194
195impl Collide<Circle> for AABB {
197 fn collide_with(&self, _other: &Circle) -> bool {
198 let mut closest: Point = _other.origin;
199 closest.x = clamp(closest.x, self.min.x, self.max.x);
200 closest.y = clamp(closest.y, self.min.y, self.max.y);
201
202 _other.collide_with(&closest)
203 }
204}
205
206impl Collide<Circle> for Circle {
208 fn collide_with(&self, _other: &Circle) -> bool {
209 let radii_sum = self.radius + _other.radius;
210 let distance: Point = _other.origin - self.origin;
211 distance.norm_squared() < radii_sum * radii_sum
212 }
213}
214
215impl Collide<Point> for Circle {
217 fn collide_with(&self, _other: &Point) -> bool {
218 let distance: Point = _other - self.origin;
219 distance.norm_squared() < self.radius * self.radius
220 }
221}
222
223impl Collide<AABB> for Circle {
225 fn collide_with(&self, _other: &AABB) -> bool {
226 _other.collide_with(self)
227 }
228}