attempt to not be twash
This commit is contained in:
parent
fca8469824
commit
35dfc37fcb
76
src/cuwusions.rs
Normal file
76
src/cuwusions.rs
Normal file
@ -0,0 +1,76 @@
|
||||
// assume collision resolution takes place before velocity resolution
|
||||
|
||||
pub fn rects_collision_resolution_pos(
|
||||
pos: (f64, f64),
|
||||
vel: (f64, f64),
|
||||
rect: (f64, f64),
|
||||
other_pos: (f64, f64),
|
||||
other_rect: (f64, f64),
|
||||
) -> (f64, f64) {
|
||||
'top_left: {
|
||||
let Some((intersection, dist)) =
|
||||
closest_point_rect_intersection(pos, vel, other_pos, other_rect)
|
||||
else {
|
||||
let (x, y) = pos;
|
||||
break 'top_left (x + vel.0, y + vel.1);
|
||||
};
|
||||
|
||||
intersection
|
||||
}
|
||||
}
|
||||
|
||||
fn point_distance(a: (f64, f64), b: (f64, f64)) -> f64 {
|
||||
((a.0 - b.0).abs().powi(2) + (a.1 - b.1).abs().powi(2)).sqrt()
|
||||
}
|
||||
|
||||
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;
|
||||
Some((x, line_y))
|
||||
}
|
||||
|
||||
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;
|
||||
Some((line_x, y))
|
||||
}
|
||||
|
||||
fn closest_point_rect_intersection(
|
||||
p0: (f64, f64),
|
||||
vel: (f64, f64),
|
||||
pos: (f64, f64),
|
||||
rect: (f64, f64),
|
||||
) -> Option<((f64, f64), f64)> {
|
||||
[
|
||||
horizontal_line_intersect(p0, vel, pos.1),
|
||||
horizontal_line_intersect(p0, vel, pos.1 + rect.1),
|
||||
vertical_line_intersect(p0, vel, pos.0 + rect.0),
|
||||
vertical_line_intersect(p0, vel, pos.0),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.map(|point| (point, point_distance(p0, point)))
|
||||
.filter(|(_, dist)| *dist <= point_distance((0.0, 0.0), vel))
|
||||
.min_by(|(_, dist_a), (_, dist_b)| dist_a.total_cmp(dist_b))
|
||||
}
|
60
src/main.rs
60
src/main.rs
@ -1,5 +1,6 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
mod cuwusions;
|
||||
mod engine;
|
||||
|
||||
use engine::{Component, System};
|
||||
@ -9,7 +10,7 @@ struct Sprite {
|
||||
sprite: engine::Sprite,
|
||||
}
|
||||
|
||||
#[derive(Component, Default, Clone)]
|
||||
#[derive(Component, Default, Clone, Debug)]
|
||||
struct RigidBody {
|
||||
pos: (f64, f64),
|
||||
vel: (f64, f64),
|
||||
@ -22,8 +23,8 @@ impl System for VelocitySystem {
|
||||
fn on_update(&self, ctx: &mut engine::Context, delta: f64) -> Result<(), engine::Error> {
|
||||
for id in query!(ctx, RigidBody) {
|
||||
let body = ctx.entity_component::<RigidBody>(id);
|
||||
body.pos.0 += body.vel.0 * delta;
|
||||
body.pos.1 += body.vel.1 * delta;
|
||||
// body.pos.0 += body.vel.0 * delta;
|
||||
// body.pos.1 += body.vel.1 * delta;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -154,51 +155,16 @@ impl System for CollisionSystem {
|
||||
continue;
|
||||
}
|
||||
let other_body = ctx.entity_component::<RigidBody>(other_id).clone();
|
||||
if rects_collide(body.rect, body.pos, other_body.rect, other_body.pos) {
|
||||
let last_pos = (
|
||||
body.pos.0 - body.vel.0 * delta,
|
||||
body.pos.1 - body.vel.1 * delta,
|
||||
);
|
||||
if rects_collide(body.rect, last_pos, other_body.rect, other_body.pos) {
|
||||
panic!()
|
||||
}
|
||||
let closest_surface = [
|
||||
(last_pos.0, last_pos.1),
|
||||
(last_pos.0, last_pos.1 + body.rect.1),
|
||||
(last_pos.0 + body.rect.0, last_pos.1),
|
||||
(last_pos.0 + body.rect.0, last_pos.1 + body.rect.1),
|
||||
]
|
||||
.into_iter()
|
||||
.filter_map(|p0| {
|
||||
point_rect_closest_surface(p0, body.vel, other_body.pos, other_body.rect)
|
||||
})
|
||||
.min_by(|(dist_a, _), (dist_b, _)| dist_a.total_cmp(dist_b))
|
||||
.map(|(_, surface)| surface)
|
||||
.ok_or("we already checked if collision happens")?;
|
||||
let new_pos = cuwusions::rects_collision_resolution_pos(
|
||||
body.pos,
|
||||
(body.vel.0 * delta, body.vel.1 * delta),
|
||||
body.rect,
|
||||
other_body.pos,
|
||||
other_body.rect,
|
||||
);
|
||||
|
||||
let collider = ctx.entity_component::<Collider>(id);
|
||||
collider.colliding_surface = Some(closest_surface.clone());
|
||||
let body = ctx.entity_component::<RigidBody>(id);
|
||||
println!("closest: {closest_surface:?} | vel: {:?}", body.vel);
|
||||
match closest_surface {
|
||||
Surface::Top => {
|
||||
body.vel.1 = 0.0;
|
||||
body.pos.1 = other_body.pos.1 - body.rect.1;
|
||||
}
|
||||
Surface::Bottom => {
|
||||
body.vel.1 = 0.0;
|
||||
body.pos.1 = other_body.pos.1 + other_body.rect.1;
|
||||
}
|
||||
Surface::Left => {
|
||||
body.vel.0 = 0.0;
|
||||
body.pos.0 = other_body.pos.0 - body.rect.0;
|
||||
}
|
||||
Surface::Right => {
|
||||
body.vel.0 = 0.0;
|
||||
body.pos.0 = other_body.pos.0 + other_body.rect.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
let body = ctx.entity_component::<RigidBody>(id);
|
||||
body.pos = new_pos;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
Loading…
Reference in New Issue
Block a user