Add the Inside version to the Collision enum (#2489)

# Objective
I think the 'collide' function inside the 'bevy/crates/bevy_sprite/src/collide_aabb.rs' file should return 'Some' if the two rectangles are fully overlapping or one is inside the other. This can happen on low-end machines when a lot of time passes between two frames because of a stutter, so a bullet for example gets inside its target. I can also think of situations where this is a valid use case even without stutters. 

## Solution
I added an 'Inside' version to the Collision enum declared in the file. And I use it, when the two rectangles are overlapping, but we can't say from which direction it happened. I gave a 'penetration depth' of minus Infinity to these cases, so that this variant only appears, when the two rectangles overlap from each side fully. I am not sure if this is the right thing to do.

Fixes #1980

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
Horváth Bálint 2022-02-01 22:40:25 +00:00
parent 4134577e64
commit c285a69f76
2 changed files with 12 additions and 17 deletions

View File

@ -8,6 +8,7 @@ pub enum Collision {
Right, Right,
Top, Top,
Bottom, Bottom,
Inside,
} }
// TODO: ideally we can remove this once bevy gets a physics system // TODO: ideally we can remove this once bevy gets a physics system
@ -27,36 +28,29 @@ pub fn collide(a_pos: Vec3, a_size: Vec2, b_pos: Vec3, b_size: Vec2) -> Option<C
// check to see if we hit on the left or right side // check to see if we hit on the left or right side
let (x_collision, x_depth) = if a_min.x < b_min.x && a_max.x > b_min.x && a_max.x < b_max.x 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) (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 { } 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) (Collision::Right, a_min.x - b_max.x)
} else { } else {
(None, 0.0) (Collision::Inside, -f32::INFINITY)
}; };
// check to see if we hit on the top or bottom side // check to see if we hit on the top or bottom side
let (y_collision, y_depth) = if a_min.y < b_min.y && a_max.y > b_min.y && a_max.y < b_max.y 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) (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 { } 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) (Collision::Top, a_min.y - b_max.y)
} else { } else {
(None, 0.0) (Collision::Inside, -f32::INFINITY)
}; };
// if we had an "x" and a "y" collision, pick the "primary" side using penetration depth // 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)) => {
if y_depth.abs() < x_depth.abs() { if y_depth.abs() < x_depth.abs() {
Some(y_collision) Some(y_collision)
} else { } else {
Some(x_collision) Some(x_collision)
} }
}
(Some(x_collision), None) => Some(x_collision),
(None, Some(y_collision)) => Some(y_collision),
(None, None) => None,
}
} else { } else {
None None
} }

View File

@ -288,6 +288,7 @@ fn ball_collision_system(
Collision::Right => reflect_x = velocity.x < 0.0, Collision::Right => reflect_x = velocity.x < 0.0,
Collision::Top => reflect_y = velocity.y < 0.0, Collision::Top => reflect_y = velocity.y < 0.0,
Collision::Bottom => reflect_y = velocity.y > 0.0, Collision::Bottom => reflect_y = velocity.y > 0.0,
Collision::Inside => { /* do nothing */ }
} }
// reflect velocity on the x-axis if we hit something on the x-axis // reflect velocity on the x-axis if we hit something on the x-axis