summaryrefslogtreecommitdiff
path: root/game_server/src/collide.rs
blob: d510a04f428e0e4d53ebb22fd3baa0c4587dfae3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::maths::{Vec2, AABox, RBox};

pub trait Collide<Rhs> {
    fn collides(&self, other: &Rhs) -> bool;
}

impl Collide<Vec2> for Vec2 {
    fn collides(&self, other: &Self) -> bool {
        self == other
    }
}

impl Collide<Vec2> for AABox {
    fn collides(&self, other: &Vec2) -> bool {
        self.pos < *other && other < &(self.pos + self.size) 
    }
}

impl Collide<AABox> for AABox {
    fn collides(&self, other: &Self) -> bool {
        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());

        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 {
        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
    }
}

impl<S, T: Collide<S>> Collide<S> for Vec<T> {
    fn collides(&self, other: &S) -> bool {
        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)));
        }
}