2021-05-14 18:45:31 +00:00
//! Utilities for detecting if and on which side two axis-aligned bounding boxes (AABB) collide.
2020-07-16 23:51:45 +00:00
use bevy_math ::{ Vec2 , Vec3 } ;
2020-06-27 04:40:09 +00:00
#[ derive(Debug) ]
pub enum Collision {
Left ,
Right ,
Top ,
Bottom ,
}
// TODO: ideally we can remove this once bevy gets a physics system
/// Axis-aligned bounding box collision with "side" detection
2021-08-24 18:07:51 +00:00
/// * a_pos and b_pos are the center positions of the rectangles, typically obtained by extracting the `translation` field from a `Transform` component
/// * a_size and b_size are the dimensions (width and height) of the rectangles.
2020-06-27 04:40:09 +00:00
pub fn collide ( a_pos : Vec3 , a_size : Vec2 , b_pos : Vec3 , b_size : Vec2 ) -> Option < Collision > {
let a_min = a_pos . truncate ( ) - a_size / 2.0 ;
let a_max = a_pos . truncate ( ) + a_size / 2.0 ;
let b_min = b_pos . truncate ( ) - b_size / 2.0 ;
let b_max = b_pos . truncate ( ) + b_size / 2.0 ;
// check to see if the two rectangles are intersecting
2020-11-17 21:40:18 +00:00
if a_min . x < b_max . x & & a_max . x > b_min . x & & a_min . y < b_max . y & & a_max . y > b_min . y {
2020-06-27 04:40:09 +00:00
// check to see if we hit on the left or right side
2020-11-17 21:40:18 +00:00
let ( x_collision , x_depth ) = if a_min . x < b_min . x & & a_max . x > b_min . x & & a_max . x < b_max . x
{
( Some ( Collision ::Left ) , b_min . x - a_max . x )
} else if a_min . x > b_min . x & & a_min . x < b_max . x & & a_max . x > b_max . x {
( Some ( Collision ::Right ) , a_min . x - b_max . x )
} else {
( None , 0.0 )
} ;
2020-06-27 04:40:09 +00:00
// check to see if we hit on the top or bottom side
2020-11-17 21:40:18 +00:00
let ( y_collision , y_depth ) = if a_min . y < b_min . y & & a_max . y > b_min . y & & a_max . y < b_max . y
{
( Some ( Collision ::Bottom ) , b_min . y - a_max . y )
} else if a_min . y > b_min . y & & a_min . y < b_max . y & & a_max . y > b_max . y {
( Some ( Collision ::Top ) , a_min . y - b_max . y )
} else {
( None , 0.0 )
} ;
2020-06-27 04:40:09 +00:00
// if we had an "x" and a "y" collision, pick the "primary" side using penetration depth
match ( x_collision , y_collision ) {
( Some ( x_collision ) , Some ( y_collision ) ) = > {
2020-12-01 08:33:52 +00:00
if y_depth . abs ( ) < x_depth . abs ( ) {
2020-06-27 04:40:09 +00:00
Some ( y_collision )
} else {
Some ( x_collision )
}
}
( Some ( x_collision ) , None ) = > Some ( x_collision ) ,
( None , Some ( y_collision ) ) = > Some ( y_collision ) ,
( None , None ) = > None ,
}
} else {
None
}
}