summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Kobert <d-kobert@web.de>2019-06-02 11:34:51 +0200
committerDennis Kobert <d-kobert@web.de>2019-06-02 11:34:51 +0200
commit23c14642b1d93905ab9bc86ca821183dd4a97f8c (patch)
tree540456613474d613ebd100b6e07d0e3a9ec93fdc
parent0f3d7f629491c8c2f2d1796bef9024d0564fbe97 (diff)
Rework collision detection to use projection
-rw-r--r--game_server/src/collide.rs113
-rw-r--r--game_server/src/maths.rs86
2 files changed, 144 insertions, 55 deletions
diff --git a/game_server/src/collide.rs b/game_server/src/collide.rs
index 7439101..d510a04 100644
--- a/game_server/src/collide.rs
+++ b/game_server/src/collide.rs
@@ -18,54 +18,31 @@ impl Collide<Vec2> for AABox {
impl Collide<AABox> for AABox {
fn collides(&self, other: &Self) -> bool {
- self.collides(&other.pos)
- || self.collides(&(other.pos + Vec2{x: other.size.x, y: 0.0}))
- || self.collides(&(other.pos + Vec2{x: 0.0, y: other.size.y}))
- || self.collides(&(other.pos + other.size))
-
- || other.collides(&(self.pos))
- || other.collides(&(self.pos + Vec2{x: self.size.x, y: 0.0}))
- || other.collides(&(self.pos + Vec2{x: 0.0, y: self.size.y}))
- || other.collides(&(self.pos + self.size))
+ self.pos.x < other.pos.x + other.size.x && other.pos.x < self.pos.x + self.size.x
+ && self.pos.y < other.pos.y + other.size.y && other.pos.y < self.pos.y + self.size.y
}
}
impl Collide<Vec2> for RBox {
fn collides(&self, other: &Vec2) -> bool {
+ let v1_diff = *other + self.v1 * (-self.v1.scalar(&other) / self.v1.distance2());
+ let v2_diff = *other + self.v2 * (-self.v2.scalar(&other) / self.v2.distance2());
- let da = self.size.norm();
- let dax = other.x - self.pos.x;
- let day = other.y - self.pos.y;
-
- let dot = dax * da.x + day * da.y;
- let px = self.pos.x + da.x * dot;
- let py = self.pos.y + da.y * dot;
-
- let p = Vec2{x: px, y: py};
- if !(self.pos < p && p < self.pos + self.size) {
- return false;
- }
-
- let ddx = other.x-px;
- let ddy = other.y-py;
- let manhattenDistance = ddx + ddy;
-
- manhattenDistance < self.w
+ self.pos < v1_diff && v1_diff < self.pos + self.v2
+ && self.pos < v2_diff && v2_diff < self.pos + self.v1
}
}
impl Collide<AABox> for RBox {
fn collides(&self, other: &AABox) -> bool {
- self.collides(&other.pos)
- || self.collides(&(other.pos + Vec2{x: other.size.x, y: 0.0}))
- || self.collides(&(other.pos + Vec2{x: 0.0, y: other.size.y}))
- || self.collides(&(other.pos + other.size))
-
- || other.collides(&(self.pos))
- || other.collides(&(self.pos + Vec2{x: self.size.x, y: 0.0}))
- || other.collides(&(self.pos + Vec2{x: 0.0, y: self.size.y}))
- || other.collides(&(self.pos + self.size))
-
+ let v1_diff = other.pos + self.v1 * (-self.v1.scalar(&other.pos) / self.v1.distance2());
+ let v2_diff = other.pos + self.v2 * (-self.v2.scalar(&other.pos) / self.v2.distance2());
+ let other_size = other.pos + other.size;
+ let v1_diff_size = other_size + self.v1 * (-self.v1.scalar(&other_size) / self.v1.distance2());
+ let v2_diff_size = other_size + self.v2 * (-self.v2.scalar(&other_size) / self.v2.distance2());
+
+ self.pos < v1_diff + other.size && v1_diff < self.pos + self.v2
+ && self.pos < v2_diff + other.size && v2_diff < self.pos + self.v1
}
}
@@ -74,3 +51,65 @@ impl<S, T: Collide<S>> Collide<S> for Vec<T> {
self.iter().any(|x| x.collides(other))
}
}
+
+#[cfg(test)]
+ mod tests {
+ use super::*;
+
+ #[test]
+ fn test_collide_dot_dot() {
+ let a = Vec2{x: 1.0, y: 7.5};
+ assert!(a.collides(&a));
+ }
+
+ #[test]
+ fn test_not_collide_dot_dot() {
+ let a = Vec2{x: 1.0, y: 7.5};
+ let b = Vec2{x: 5.0, y: 7.5};
+ assert!(!a.collides(&b));
+ }
+
+ #[test]
+ fn test_collide_aabox_dot() {
+ let a = Vec2{x: 1.0, y: 2.5};
+ let b = Vec2{x: 3.0, y: 7.5};
+ let c = Vec2{x: 1.5, y: 5.0};
+ let aa_box = AABox{pos: a, size: b};
+
+ assert!(aa_box.collides(&c));
+ }
+
+ #[test]
+ fn test_not_collide_aabox_aabox() {
+ let a = Vec2{x: 1.0, y: 7.5};
+ let b = Vec2{x: 3.0, y: 2.5};
+ let c = Vec2{x: 0.5, y: 5.0};
+ let aa_box = AABox{pos: a, size: b};
+ let a = Vec2{x: 1.0, y: 7.5};
+ let b = Vec2{x: 3.0, y: 2.5};
+ let c = Vec2{x: 0.5, y: 5.0};
+ let aa_box = AABox{pos: a, size: b};
+
+ assert!(!(aa_box.collides(&c)));
+ }
+
+ #[test]
+ fn test_collide_Rbox_dot() {
+ let a = Vec2{x: 1.0, y: 2.5};
+ let b = Vec2{x: 3.0, y: 7.5};
+ let c = Vec2{x: 1.5, y: 5.0};
+ let aa_box = AABox{pos: a, size: b};
+
+ assert!(aa_box.collides(&c));
+ }
+
+ #[test]
+ fn test_not_collide_Rbox_dot() {
+ let a = Vec2{x: 1.0, y: 7.5};
+ let b = Vec2{x: 3.0, y: 2.5};
+ let c = Vec2{x: 0.5, y: 5.0};
+ let aa_box = AABox{pos: a, size: b};
+
+ assert!(!(aa_box.collides(&c)));
+ }
+}
diff --git a/game_server/src/maths.rs b/game_server/src/maths.rs
index 66c5bca..cc6c777 100644
--- a/game_server/src/maths.rs
+++ b/game_server/src/maths.rs
@@ -48,9 +48,19 @@ impl std::ops::Neg for Vec2 {
}
}
+impl std::ops::Mul<f32> for Vec2 {
+ type Output = Self;
+ fn mul(self, scale: f32) -> Self {
+ Self {
+ x: self.x * scale,
+ y: -self.y * scale
+ }
+ }
+}
+
impl std::cmp::PartialOrd for Vec2 {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
- if self.x < other.x && self.y < other.y {
+ if self.x <= other.x && self.y <= other.y {
Some(std::cmp::Ordering::Less)
} else if self.x > other.x && self.y > other.y {
Some(std::cmp::Ordering::Greater)
@@ -75,7 +85,11 @@ impl Vec2 {
}
pub fn distance2(&self) -> f32 {
- self.x * self.x + self.y * self.y
+ self.scalar(self)
+ }
+
+ pub fn scalar(&self, other: &Vec2) -> f32 {
+ self.x * other.x + self.y * other.y
}
pub fn norm(&self) -> Vec2 {
@@ -137,12 +151,12 @@ impl std::cmp::Eq for AABox {}
#[derive(Clone, Copy, Debug)]
pub struct RBox {
- /// Point 1
+ /// origin
pub pos: Vec2,
- /// Point 2
- pub size: Vec2,
- /// Width Attention manhatten distance!!!
- pub w: f32,
+ /// Vwctor1
+ pub v1: Vec2,
+ /// Vector2
+ pub v2: Vec2,
}
impl std::ops::Add<Vec2> for RBox {
@@ -150,8 +164,8 @@ impl std::ops::Add<Vec2> for RBox {
fn add(self, other: Vec2) -> Self {
Self {
pos: self.pos + other,
- size: self.size,
- w: self.w,
+ v1: self.v1,
+ v2: self.v2,
}
}
}
@@ -167,8 +181,8 @@ impl std::ops::Sub<Vec2> for RBox {
fn sub(self, other: Vec2) -> Self {
Self {
pos: self.pos + other,
- size: self.size + other,
- w: self.w,
+ v1: self.v1 + other,
+ v2: self.v2,
}
}
}
@@ -182,8 +196,8 @@ impl std::ops::SubAssign<Vec2> for RBox {
impl std::cmp::PartialEq for RBox {
fn eq(&self, other: &Self) -> bool {
self.pos == other.pos
- && self.size == other.size
- && f32::abs(self.w - other.w) < 1e-8
+ && self.v1 == other.v1
+ && self.v1 == self.v2
}
}
@@ -195,6 +209,39 @@ mod tests {
use super::*;
#[test]
+ fn test_less_vec2() {
+ let a = Vec2{x: 1.0, y: 7.5};
+ let b = Vec2{x: -3.0, y: 2.5};
+
+ assert!(b < a);
+ }
+
+ #[test]
+ fn test_less_vec2_fail() {
+ let a = Vec2{x: 1.0, y: 7.5};
+ let b = Vec2{x: 3.0, y: 2.5};
+
+ assert!(!(a < b));
+ }
+
+ #[test]
+ fn test_greater_vec2() {
+ let a = Vec2{x: 1.0, y: 7.5};
+ let b = Vec2{x: -3.0, y: 2.5};
+
+ assert!(a > b);
+ }
+
+ #[test]
+ fn test_greater_vec2_fail() {
+ let a = Vec2{x: 1.0, y: 7.5};
+ let b = Vec2{x: 3.0, y: 2.5};
+
+ assert!(!(a > b));
+ }
+
+
+ #[test]
fn test_add_vec2() {
let a = Vec2{x: 1.0, y: 7.5};
let b = Vec2{x: -3.0, y: 2.5};
@@ -233,6 +280,7 @@ mod tests {
assert!(f32::abs(a.distance2() - 5.0) < 1e8);
}
+
#[test]
fn test_norm_vec2() {
let a = Vec2{x: 2.0, y: -2.0};
@@ -267,8 +315,9 @@ mod tests {
fn test_add_rbox_vec2() {
let a = Vec2{x: 1.0, y: 7.5};
let b = Vec2{x: -3.0, y: 2.5};
- let mut aa_box = RBox{pos: a, size: b, w: 8.0};
- let bb_box = RBox{pos: a + b,size: b, w: 8.0};
+ let c = Vec2{x: -3.0, y: 2.5};
+ let mut aa_box = RBox{pos: a, v1: b, v2: c};
+ let bb_box = RBox{pos: a + b, v1: b, v2: c};
aa_box += b;
assert_eq!(aa_box, bb_box);
@@ -278,10 +327,11 @@ mod tests {
fn test_sub_rbox_vec2() {
let a = Vec2{x: 1.0, y: 7.5};
let b = Vec2{x: -3.0, y: 2.5};
- let mut aa_box = RBox{pos: a, size: b, w: 8.0};
- let bb_box = RBox{pos: a - b,size: b, w: 8.0};
+ let c = Vec2{x: -3.0, y: 2.5};
+ let mut aa_box = RBox{pos: a, v1: b, v2: c};
+ let bb_box = RBox{pos: a - b, v1: b, v2: c};
aa_box -= b;
assert_eq!(aa_box, bb_box);
}
-} \ No newline at end of file
+}