Look into better collision resolution which will deflect objects

This commit is contained in:
Savanni D'Gerinel 2024-02-07 08:16:06 -05:00
parent d62454545f
commit 1f2611dda4
1 changed files with 30 additions and 14 deletions

View File

@ -1,6 +1,6 @@
use crate::profile; use crate::profile;
use std::{ use std::{
ops::{Mul, Neg}, ops::{Mul, Neg, Sub},
sync::{Arc, RwLock}, sync::{Arc, RwLock},
}; };
@ -35,6 +35,16 @@ struct Vector {
dy: f64, dy: f64,
} }
impl Sub for Vector {
type Output = Vector;
fn sub(self, rhs: Vector) -> Self::Output {
Self {
dx: rhs.dx - self.dx,
dy: rhs.dy - self.dy,
}
}
}
impl Neg for Vector { impl Neg for Vector {
type Output = Vector; type Output = Vector;
fn neg(self) -> Self { fn neg(self) -> Self {
@ -100,51 +110,57 @@ impl World {
pub fn next(&self, delta_t: std::time::Duration) { pub fn next(&self, delta_t: std::time::Duration) {
self.move_objects(delta_t); self.move_objects(delta_t);
self.resolve_collisions(); self.resolve_overlaps();
} }
fn move_objects(&self, delta_t: std::time::Duration) { fn move_objects(&self, delta_t: std::time::Duration) {
/* First, need to resolve collisions between objects and ensure that they bounce in the correct direction. This will only resolve the initial collision in a step. Additional collisions are undetectable, so we will resolve those with the overlap code. */
for grain in self.grains.write().unwrap().iter_mut() { for grain in self.grains.write().unwrap().iter_mut() {
grain.move_by(delta_t); grain.move_by(delta_t);
} }
} }
fn resolve_collisions(&self) {} /* Once all movement has been calculated out, some objects are probably still going to be overlapping. */
fn resolve_overlaps(&self) {}
} }
pub trait Collision { pub trait Collision {
type Other; type Other;
fn overlap(&self, other: &Self::Other) -> Option<(f64, Vector)>; fn overlap(&self, other: &Self::Other) -> Option<f64>;
fn resolve_collision(&mut self, other: &mut Self::Other); fn resolve_collision(&mut self, other: &mut Self::Other);
} }
impl Collision for Grain { impl Collision for Grain {
type Other = Grain; type Other = Grain;
fn overlap(&self, other: &Self::Other) -> Option<(f64, Vector)> { fn overlap(&self, other: &Self::Other) -> Option<f64> {
let radii = (self.radius + other.radius) * (self.radius + other.radius); let radii = (self.radius + other.radius) * (self.radius + other.radius);
let distance = self.location.distance_sq(&other.location); let distance = self.location.distance_sq(&other.location);
if distance < radii { if distance < radii {
let dx = other.location.x - self.location.x; let dx = other.location.x - self.location.x;
let dy = other.location.y - self.location.y; let dy = other.location.y - self.location.y;
Some((radii.sqrt() - distance.sqrt(), Vector { dx, dy })) Some(radii.sqrt() - distance.sqrt())
} else { } else {
None None
} }
} }
fn resolve_collision(&mut self, other: &mut Self::Other) { fn resolve_collision(&mut self, other: &mut Self::Other) {
// between every two objects calculate out the point and angle of incidence for a collision.
// Start with i, the intersection distance, which is the addition of the radii of both objects.
// Then calculate t = i / |v1 - v2|
// I don't think that my equation takes into account two objects that don't collide
/*
match self.overlap(other) { match self.overlap(other) {
Some((overlap, v)) => { Some(overlap) => {
let max_overlap = self.radius + other.radius; // a collision has occured. First, undo the overlap by moving both pieces backwards to their intersection points
let resolution = overlap / max_overlap; // once reversed, calculate percentage of travel already done
let v = v * resolution; // next, calculate the bounce vectors
println!("{:?} {} {} {}", v, overlap, max_overlap, resolution); // finally, apply the bounce vectors, scaled by remaining travel percentage
self.translate(-v);
other.translate(v);
} }
None => {} None => {}
} }
*/
} }
} }
@ -171,7 +187,7 @@ mod test {
velocity: Vector { dx: 0., dy: 0. }, velocity: Vector { dx: 0., dy: 0. },
}; };
assert_matches!(grain_1.overlap(&grain_2), Some((overlap, _)) => { assert_matches!(grain_1.overlap(&grain_2), Some(overlap) => {
assert!(within(overlap, 19., 0.1)); assert!(within(overlap, 19., 0.1));
} ); } );
assert_matches!(grain_1.overlap(&grain_3), None); assert_matches!(grain_1.overlap(&grain_3), None);