Look into better collision resolution which will deflect objects
This commit is contained in:
parent
d62454545f
commit
1f2611dda4
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue