diff --git a/src/main.rs b/src/main.rs index 51c153f..4b99366 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,7 +44,6 @@ impl Rect { } pub fn point_collides(&self, pos: (f64, f64), point: (f64, f64)) -> bool { - println!("point: {point:?}"); pos.0 + self.width < point.0 && pos.0 >= point.0 && pos.1 + self.height < point.1 @@ -74,22 +73,37 @@ struct Collider { resolve: bool, } -fn horizontal_line_intersect(p0: (f64, f64), vel: (f64, f64), line_y: f64) -> (f64, f64) { +fn horizontal_line_intersect(p0: (f64, f64), vel: (f64, f64), line_y: f64) -> Option<(f64, f64)> { + if vel.1 == 0.0 { + // exclusively going left or right, ergo there's no collision with a horizontal line + return None; + } else if vel.0 == 0.0 { + // no change in x, ergo the intersect must be at p0_x + return Some((p0.0, line_y)); + } // y = ax + b let a = vel.1 / vel.0; let b = p0.1 - p0.0 * a; let x = (line_y - b) / a; - (x, line_y) + Some((x, line_y)) } -fn vertical_line_intersect(p0: (f64, f64), vel: (f64, f64), line_x: f64) -> (f64, f64) { +fn vertical_line_intersect(p0: (f64, f64), vel: (f64, f64), line_x: f64) -> Option<(f64, f64)> { + if vel.0 == 0.0 { + // exclusively going up or down, ergo there's no collision with a vertical line + return None; + } else if vel.1 == 0.0 { + // no change in y, ergo the intersect must be at p0_y + return Some((line_x, p0.1)); + } + // // y = ax + b let a = vel.1 / vel.0; let b = p0.1 - p0.0 * a; let y = a * line_x + b; - (line_x, y) + Some((line_x, y)) } #[derive(Debug)] @@ -110,12 +124,20 @@ fn closest_surface_for_point_and_rectangle_and_your_mom( rect_pos: (f64, f64), rect: &Rect, ) -> Option<(f64, Surface)> { - [ + let closest_horizontal_intersect = [ (horizontal_line_intersect(p0, vel, rect_pos.1), Surface::Top), ( horizontal_line_intersect(p0, vel, rect_pos.1 + rect.height), Surface::Bottom, ), + ] + .into_iter() + .filter_map(|(intersect, surface)| intersect.map(|intersect| (intersect, surface))) + .filter(|&((x, _), _)| x >= rect_pos.0 && x < rect_pos.0 + rect.width) + .map(|(point, surface)| (point_distance(p0, point), surface)) + .min_by(|(dist_a, _), (dist_b, _)| dist_a.total_cmp(&dist_b)); + + let closest_vertical_intersect = [ (vertical_line_intersect(p0, vel, rect_pos.0), Surface::Left), ( vertical_line_intersect(p0, vel, rect_pos.0 + rect.width), @@ -123,8 +145,21 @@ fn closest_surface_for_point_and_rectangle_and_your_mom( ), ] .into_iter() + .filter_map(|(intersect, surface)| intersect.map(|intersect| (intersect, surface))) + .filter(|&((_, y), _)| y >= rect_pos.1 && y < rect_pos.1 + rect.height) .map(|(point, surface)| (point_distance(p0, point), surface)) - .min_by(|(dist_a, _), (dist_b, _)| dist_a.total_cmp(&dist_b)) + .min_by(|(dist_a, _), (dist_b, _)| dist_a.total_cmp(&dist_b)); + + match (closest_horizontal_intersect, closest_vertical_intersect) { + (Some(left), Some(right)) => { + if right.0 < left.0 { + Some(right) + } else { + Some(left) + } + } + (None, v) | (v, None) => v, + } } struct CollisionSystem; @@ -163,14 +198,11 @@ impl System for CollisionSystem { &other_rect, ) }) - .inspect(|v| println!("item: {v:?}")) .filter_map(std::convert::identity) .min_by(|(dist_a, _), (dist_b, _)| dist_a.total_cmp(&dist_b)) .map(|(_, surface)| surface) .ok_or_else(|| "we already checked if collision happens")?; - println!("surface found: {closest_surface:?}"); - let body = ctx.entity_component::(id); match closest_surface { Surface::Top => { @@ -183,11 +215,11 @@ impl System for CollisionSystem { } Surface::Left => { body.vel.0 = 0.0; - body.pos.0 = other_body.pos.0 + other_rect.width; + body.pos.0 = other_body.pos.0 - rect.width; } Surface::Right => { body.vel.0 = 0.0; - body.pos.0 = other_body.pos.0 - rect.width; + body.pos.0 = other_body.pos.0 + other_rect.width; } } } @@ -313,6 +345,7 @@ fn main() { RigidBody { pos: (400.0, 400.0), gravity: true, + vel: (0.0, -600.0), ..Default::default() }, Rect { @@ -326,12 +359,25 @@ fn main() { spawn!( &mut context, RigidBody { - pos: (0.0, 720.0), + pos: (184.0, 540.0), ..Default::default() }, Rect { - width: 1000.0, - height: 25.0 + width: 960.0, + height: 128.0 + }, + Collider { resolve: false }, + ); + + spawn!( + &mut context, + RigidBody { + pos: (872.0, 360.0), + ..Default::default() + }, + Rect { + width: 388.0, + height: 48.0 }, Collider { resolve: false }, );