Skip to main content

dreamwell_engine/physics/
force_fields.rs

1use serde::{Deserialize, Serialize};
2
3/// Force field kind — type of spatial force applied to particles.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
5pub enum ForceFieldKind {
6    Gravity,
7    Drag,
8    Damping,
9    Directional,
10    Radial,
11    Attractor,
12    Repulsor,
13    Vortex,
14    Orbital,
15    Turbulence,
16    CurlNoise,
17    Wind,
18    Buoyancy,
19    CustomVectorField,
20}
21
22/// Force binding — references a force field by kind with strength and radius.
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct ForceBinding {
25    pub kind: ForceFieldKind,
26    pub strength: f32,
27    pub radius: f32,
28}
29
30/// Force field descriptor — full definition of a spatial force field.
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct ForceFieldDescriptor {
33    pub kind: ForceFieldKind,
34    pub position: [f32; 3],
35    pub direction: [f32; 3],
36    pub strength: f32,
37    pub radius: f32,
38    pub falloff: f32,
39    pub noise_frequency: f32,
40    pub noise_amplitude: f32,
41}
42
43impl Default for ForceFieldDescriptor {
44    fn default() -> Self {
45        Self {
46            kind: ForceFieldKind::Gravity,
47            position: [0.0, 0.0, 0.0],
48            direction: [0.0, -1.0, 0.0],
49            strength: 9.81,
50            radius: f32::MAX,
51            falloff: 0.0,
52            noise_frequency: 0.0,
53            noise_amplitude: 0.0,
54        }
55    }
56}
57
58impl ForceFieldKind {
59    pub const ALL: &[ForceFieldKind] = &[
60        Self::Gravity,
61        Self::Drag,
62        Self::Damping,
63        Self::Directional,
64        Self::Radial,
65        Self::Attractor,
66        Self::Repulsor,
67        Self::Vortex,
68        Self::Orbital,
69        Self::Turbulence,
70        Self::CurlNoise,
71        Self::Wind,
72        Self::Buoyancy,
73        Self::CustomVectorField,
74    ];
75
76    pub fn name(&self) -> &'static str {
77        match self {
78            Self::Gravity => "Gravity",
79            Self::Drag => "Drag",
80            Self::Damping => "Damping",
81            Self::Directional => "Directional",
82            Self::Radial => "Radial",
83            Self::Attractor => "Attractor",
84            Self::Repulsor => "Repulsor",
85            Self::Vortex => "Vortex",
86            Self::Orbital => "Orbital",
87            Self::Turbulence => "Turbulence",
88            Self::CurlNoise => "Curl Noise",
89            Self::Wind => "Wind",
90            Self::Buoyancy => "Buoyancy",
91            Self::CustomVectorField => "Custom Vector Field",
92        }
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn force_field_kind_all() {
102        assert_eq!(ForceFieldKind::ALL.len(), 14);
103    }
104
105    #[test]
106    fn force_field_descriptor_default() {
107        let f = ForceFieldDescriptor::default();
108        assert_eq!(f.kind, ForceFieldKind::Gravity);
109        assert_eq!(f.direction, [0.0, -1.0, 0.0]);
110    }
111
112    #[test]
113    fn force_field_serde() {
114        let f = ForceFieldDescriptor {
115            kind: ForceFieldKind::Vortex,
116            position: [1.0, 2.0, 3.0],
117            direction: [0.0, 1.0, 0.0],
118            strength: 5.0,
119            radius: 10.0,
120            falloff: 1.0,
121            noise_frequency: 0.0,
122            noise_amplitude: 0.0,
123        };
124        let json = serde_json::to_string(&f).unwrap();
125        let restored: ForceFieldDescriptor = serde_json::from_str(&json).unwrap();
126        assert_eq!(restored.kind, ForceFieldKind::Vortex);
127    }
128}