Skip to main content

pfx_physics/rigid/
drive.rs

1use pfx_core::motion::Spring;
2
3use super::Pose;
4use super::convert::{Iso, iso, lerp_iso};
5
6#[derive(Clone, Copy, Debug)]
7pub struct Ease {
8    pub from: Pose,
9    pub to: Pose,
10    pub duration: f32,
11    pub elapsed: f32,
12    pub curve: fn(f32) -> f32,
13}
14
15impl Ease {
16    pub fn new(from: Pose, to: Pose, duration: f32, curve: fn(f32) -> f32) -> Self {
17        Self {
18            from,
19            to,
20            duration,
21            elapsed: 0.0,
22            curve,
23        }
24    }
25
26    pub fn done(&self) -> bool {
27        self.elapsed >= self.duration
28    }
29
30    fn at(&self) -> Iso {
31        let t = if self.duration > 0.0 {
32            (self.elapsed / self.duration).clamp(0.0, 1.0)
33        } else {
34            1.0
35        };
36        lerp_iso(&iso(self.from), &iso(self.to), (self.curve)(t))
37    }
38}
39
40#[derive(Clone, Copy, Debug)]
41pub enum Drive {
42    Spring(Spring<[f32; 3]>),
43    Ease(Ease),
44}
45
46impl Drive {
47    pub fn spring(stiffness: f32, position: [f32; 3]) -> Self {
48        Self::Spring(Spring::at(stiffness, position))
49    }
50
51    pub fn ease(from: Pose, to: Pose, duration: f32, curve: fn(f32) -> f32) -> Self {
52        Self::Ease(Ease::new(from, to, duration, curve))
53    }
54
55    pub fn settled(&self) -> bool {
56        match self {
57            Self::Spring(spring) => spring.settled(),
58            Self::Ease(ease) => ease.done(),
59        }
60    }
61
62    pub(crate) fn advance(&mut self, dt: f32, current: &Iso) -> Iso {
63        match self {
64            Self::Spring(spring) => {
65                spring.step(dt);
66                let [x, y, z] = spring.value;
67                Iso::from_parts(super::convert::Vec3::new(x, y, z), current.rotation)
68            }
69            Self::Ease(ease) => {
70                ease.elapsed = (ease.elapsed + dt).min(ease.duration.max(0.0));
71                ease.at()
72            }
73        }
74    }
75}