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
#![deny(missing_docs)]

/*!
This crate contains a sphere collider, which implements the collide trait from the `collide` crate.
**/

use collide::{Collider, CollisionInfo};
use num_traits::real::Real;
use vector_space::{InnerSpace, VectorSpace};

#[derive(Copy, Clone)]
/// The sphere collider.
pub struct Sphere<V: VectorSpace> {
    /// The position of the sphere collider.
    pub pos: V,
    /// The radius of the sphere collider.
    pub rad: V::Scalar,
}

impl<V: InnerSpace> Sphere<V> {
    /// Creates a new sphere collider from a position and a radius.
    pub fn new(pos: V, rad: V::Scalar) -> Self {
        Self { pos, rad }
    }
}

impl<V: InnerSpace> Collider for Sphere<V> {
    type Vector = V;

    fn check_collision(&self, other: &Self) -> bool {
        let rad = self.rad + other.rad;
        let rad2 = rad * rad;
        let vec = other.pos - self.pos;
        vec.magnitude2() <= rad2
    }

    fn collision_info(&self, other: &Self) -> Option<CollisionInfo<Self::Vector>> {
        let rad = self.rad + other.rad;
        let rad2 = rad * rad;
        let vec = other.pos - self.pos;
        let mag2 = vec.magnitude2();
        if mag2 <= rad2 {
            let mag = mag2.sqrt();
            let direction = vec / mag;
            Some(CollisionInfo {
                self_contact: self.pos + direction * self.rad,
                other_contact: other.pos - direction * other.rad,
                vector: direction * (mag - rad),
            })
        } else {
            None
        }
    }
}