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)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
mod cuwusions;
|
||||||
mod engine;
|
mod engine;
|
||||||
|
|
||||||
use engine::{Component, System};
|
use engine::{Component, System};
|
||||||
@ -9,7 +10,7 @@ struct Sprite {
|
|||||||
sprite: engine::Sprite,
|
sprite: engine::Sprite,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Default, Clone)]
|
#[derive(Component, Default, Clone, Debug)]
|
||||||
struct RigidBody {
|
struct RigidBody {
|
||||||
pos: (f64, f64),
|
pos: (f64, f64),
|
||||||
vel: (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> {
|
fn on_update(&self, ctx: &mut engine::Context, delta: f64) -> Result<(), engine::Error> {
|
||||||
for id in query!(ctx, RigidBody) {
|
for id in query!(ctx, RigidBody) {
|
||||||
let body = ctx.entity_component::<RigidBody>(id);
|
let body = ctx.entity_component::<RigidBody>(id);
|
||||||
body.pos.0 += body.vel.0 * delta;
|
// body.pos.0 += body.vel.0 * delta;
|
||||||
body.pos.1 += body.vel.1 * delta;
|
// body.pos.1 += body.vel.1 * delta;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -154,51 +155,16 @@ impl System for CollisionSystem {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let other_body = ctx.entity_component::<RigidBody>(other_id).clone();
|
let other_body = ctx.entity_component::<RigidBody>(other_id).clone();
|
||||||
if rects_collide(body.rect, body.pos, other_body.rect, other_body.pos) {
|
let new_pos = cuwusions::rects_collision_resolution_pos(
|
||||||
let last_pos = (
|
body.pos,
|
||||||
body.pos.0 - body.vel.0 * delta,
|
(body.vel.0 * delta, body.vel.1 * delta),
|
||||||
body.pos.1 - body.vel.1 * delta,
|
body.rect,
|
||||||
);
|
other_body.pos,
|
||||||
if rects_collide(body.rect, last_pos, other_body.rect, other_body.pos) {
|
other_body.rect,
|
||||||
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 collider = ctx.entity_component::<Collider>(id);
|
let body = ctx.entity_component::<RigidBody>(id);
|
||||||
collider.colliding_surface = Some(closest_surface.clone());
|
body.pos = new_pos;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
Loading…
Reference in New Issue
Block a user