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 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);
|
||||||
|
|
Loading…
Reference in New Issue