summaryrefslogtreecommitdiffstats
path: root/src/physics.rs
blob: 458f1e7ca2d7fa6309b506666fe3a200b8d29810 (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
pub(crate) use error::{Error, Result};
pub use point::Point;
pub use vector::Vector;

mod error;
mod point;
mod vector;

pub trait Physics {
    fn tick_time<E: crate::Engine>(&mut self, engine: E) -> Result<()>;
}

pub trait Position {
    fn get_position(&self) -> Point;
    fn set_position<P: Into<Point>>(&mut self, position: P) -> Result<()>;
}

pub trait Velocity: Position {
    fn get_velocity(&self) -> Vector;

    fn set_velocity<V: Into<Vector>>(&mut self, velocity: V) -> Result<()>;

    fn apply_velocity(&mut self) -> Result<()> {
        self.set_position(self.get_position() + self.get_velocity())
    }

    fn reset_velocity(&mut self) -> Result<()> {
        self.set_velocity(Vector::default())
    }
}

pub trait Collider {
    fn collision_map(&self) -> &Vec<Point>;
}

pub trait Collidable: Collider + Velocity {
    fn next_collision_map(&self) -> Vec<Point> {
        let velocity = self.get_velocity();
        self.collision_map().iter().map(|p| *p + velocity).collect()
    }

    fn check_collision<C: Collider>(&self, colliders: C) -> Result<()> {
        let collision = self
            .next_collision_map()
            .iter()
            .zip(colliders.collision_map())
            .filter_map(|(p1, p2)| p1.eq(p2).then_some(*p1))
            .collect::<Vec<point::Point>>();

        if !collision.is_empty() {
            Ok(())
        } else {
            Err(Error::Collision(collision))
        }
    }

    fn check_colliders<C: Collider>(&self, colliders: Vec<C>) -> Result<()> {
        for collidable in colliders {
            self.check_collision(collidable)?
        }
        Ok(())
    }
}

impl<T: Velocity + Collidable> Physics for T {
    fn tick_time<E: crate::Engine>(&mut self, engine: E) -> Result<()> {
        self.check_colliders(engine.get_colliders())?;
        self.apply_velocity()
    }
}