aboutsummaryrefslogtreecommitdiff
path: root/plugins/movement/src/reducer.rs
blob: 3885f2616bdbb4824c21f3b39d8679c4eae48d62 (plain) (blame)
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
use bevy::{ecs::component::Component, math::Vec3};

use crate::Velocity;

/// Controls how Velocity is reduced
#[derive(Component)]
pub enum VelocityReducer {
    /// Sync mode, only applies the current Velocity to translation each time, does not reduce itself
    Sync,

    /// Move mode, directly zeroes out the velocity (momentum is transferred to translation)
    Move,

    /// Constant reduction mode, reduces by a fixed amount each time until it becomes Vec3::ZERO
    Reduce(Vec3),

    /// Lerp, reduces velocity using linear interpolation each time until it becomes Vec3::ZERO
    Lerp(f32),

    /// Function, calls a custom function to process velocity
    Func(Box<dyn Fn(Vec3) -> Vec3 + Send + Sync + 'static>),
}

impl VelocityReducer {
    /// Calculates velocity reduction, writing the result back to the Velocity component
    pub fn calculate(&self, origin: &mut Velocity) {
        self.calculate_vec(&mut *origin);
    }

    /// Calculates velocity reduction, writing the result back to Vec3
    pub fn calculate_vec(&self, origin_vec: &mut Vec3) {
        match self {
            VelocityReducer::Sync => {
                // DO NOTHING
            }
            VelocityReducer::Move => {
                *origin_vec = Vec3::ZERO;
            }
            VelocityReducer::Reduce(vec3) => {
                let mut vec = *origin_vec - *vec3;
                // Handle direction: if the sign flips, clamp to zero
                if (origin_vec.x >= 0.0 && vec.x < 0.0) || (origin_vec.x <= 0.0 && vec.x > 0.0) {
                    vec.x = 0.0;
                }
                if (origin_vec.y >= 0.0 && vec.y < 0.0) || (origin_vec.y <= 0.0 && vec.y > 0.0) {
                    vec.y = 0.0;
                }
                if (origin_vec.z >= 0.0 && vec.z < 0.0) || (origin_vec.z <= 0.0 && vec.z > 0.0) {
                    vec.z = 0.0;
                }
                *origin_vec = vec;
            }
            VelocityReducer::Lerp(lerp) => {
                let lerp = lerp.clamp(0., 1.);
                *origin_vec = origin_vec.lerp(Vec3::ZERO, lerp);
            }
            VelocityReducer::Func(fn_mut) => {
                *origin_vec = fn_mut(*origin_vec);
            }
        }
    }
}