Skip to main content

mittens_engine/engine/ecs/component/
input_transform_mode.rs

1use crate::engine::ecs::component::{Component, ComponentRef};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum ForwardAxis {
5    /// Classic 2D-ish behavior: W/S move along -Y/+Y.
6    Y,
7    /// 3D-friendly behavior: W/S move along -Z/+Z.
8    Z,
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum RollAxis {
13    X,
14    Y,
15    Z,
16}
17
18/// Input mode component that controls which axis is treated as "forward" for WASD.
19///
20/// Intended topology:
21/// InputComponent -> (InputTransformModeComponent?)
22/// InputComponent -> TransformComponent
23#[derive(Debug, Clone)]
24pub struct InputTransformModeComponent {
25    pub forward_axis: ForwardAxis,
26    pub roll_axis: RollAxis,
27    pub rotation_enabled: bool,
28    pub translation_basis_source: Option<ComponentRef>,
29
30    /// If true, rotations are applied in world axes (FPS-style).
31    /// If false, rotations are applied in local space (current behavior).
32    pub fps_rotation: bool,
33}
34
35impl InputTransformModeComponent {
36    pub fn forward_y() -> Self {
37        Self {
38            forward_axis: ForwardAxis::Y,
39            roll_axis: RollAxis::Z,
40            rotation_enabled: true,
41            translation_basis_source: None,
42            fps_rotation: false,
43        }
44    }
45
46    pub fn forward_z() -> Self {
47        Self {
48            forward_axis: ForwardAxis::Z,
49            roll_axis: RollAxis::Z,
50            rotation_enabled: true,
51            translation_basis_source: None,
52            fps_rotation: false,
53        }
54    }
55
56    pub fn with_rotation_disabled(mut self) -> Self {
57        self.rotation_enabled = false;
58        self
59    }
60
61    pub fn with_translation_basis_source(mut self, source: ComponentRef) -> Self {
62        self.translation_basis_source = Some(source);
63        self
64    }
65
66    pub fn with_fps_rotation(mut self) -> Self {
67        self.fps_rotation = true;
68        self
69    }
70
71    pub fn with_roll_axis_y(mut self) -> Self {
72        self.roll_axis = RollAxis::Y;
73        self
74    }
75
76    pub fn with_roll_axis_z(mut self) -> Self {
77        self.roll_axis = RollAxis::Z;
78        self
79    }
80}
81
82impl Default for InputTransformModeComponent {
83    fn default() -> Self {
84        Self::forward_y()
85    }
86}
87
88impl Component for InputTransformModeComponent {
89    fn name(&self) -> &'static str {
90        "input_transform_mode"
91    }
92
93    fn as_any(&self) -> &dyn std::any::Any {
94        self
95    }
96
97    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
98        self
99    }
100
101    fn to_mms_ast(
102        &self,
103        _world: &crate::engine::ecs::World,
104    ) -> crate::scripting::ast::ComponentExpression {
105        use crate::engine::ecs::component::ce_helpers::*;
106        let ctor = match self.forward_axis {
107            ForwardAxis::Y => "forward_y",
108            ForwardAxis::Z => "forward_z",
109        };
110        let mut ce = ce_call("InputTransformMode", ctor, vec![]);
111        if matches!(self.roll_axis, RollAxis::Y) {
112            ce = ce.with_call("roll_axis_y", vec![]);
113        }
114        if !self.rotation_enabled {
115            ce = ce.with_call("rotation_disabled", vec![]);
116        }
117        if self.fps_rotation {
118            ce = ce.with_call("fps_rotation", vec![]);
119        }
120        if let Some(source) = &self.translation_basis_source {
121            let expr = match source {
122                ComponentRef::Guid(u) => {
123                    crate::scripting::ast::Expression::String(format!("@uuid:{u}"))
124                }
125                ComponentRef::Query(s) => crate::scripting::ast::Expression::String(s.clone()),
126            };
127            ce = ce.with_call("translation_basis", vec![expr]);
128        }
129        ce
130    }
131}