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 std::{
ops::{Mul, Neg},
ops::{Mul, Neg, Sub},
sync::{Arc, RwLock},
};
@ -35,6 +35,16 @@ struct Vector {
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 {
type Output = Vector;
fn neg(self) -> Self {
@ -100,51 +110,57 @@ impl World {
pub fn next(&self, delta_t: std::time::Duration) {
self.move_objects(delta_t);
self.resolve_collisions();
self.resolve_overlaps();
}
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() {
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 {
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);
}
impl Collision for 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 distance = self.location.distance_sq(&other.location);
if distance < radii {
let dx = other.location.x - self.location.x;
let dy = other.location.y - self.location.y;
Some((radii.sqrt() - distance.sqrt(), Vector { dx, dy }))
Some(radii.sqrt() - distance.sqrt())
} else {
None
}
}
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) {
Some((overlap, v)) => {
let max_overlap = self.radius + other.radius;
let resolution = overlap / max_overlap;
let v = v * resolution;
println!("{:?} {} {} {}", v, overlap, max_overlap, resolution);
self.translate(-v);
other.translate(v);
Some(overlap) => {
// a collision has occured. First, undo the overlap by moving both pieces backwards to their intersection points
// once reversed, calculate percentage of travel already done
// next, calculate the bounce vectors
// finally, apply the bounce vectors, scaled by remaining travel percentage
}
None => {}
}
*/
}
}
@ -171,7 +187,7 @@ mod test {
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_matches!(grain_1.overlap(&grain_3), None);