From 1f2611dda48ce522a9c0eec1fcba997b8b67b98c Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Wed, 7 Feb 2024 08:16:06 -0500 Subject: [PATCH] Look into better collision resolution which will deflect objects --- falling-sand/src/physics.rs | 44 +++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/falling-sand/src/physics.rs b/falling-sand/src/physics.rs index a95fdde..ffbe4e5 100644 --- a/falling-sand/src/physics.rs +++ b/falling-sand/src/physics.rs @@ -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; 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 { 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);