Skip to main content

impetus/
body.rs

1//! Rigid bodies — static, dynamic, kinematic.
2
3use serde::{Deserialize, Serialize};
4
5/// Unique handle to a rigid body.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
7pub struct BodyHandle(pub u64);
8
9/// Body type.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11#[non_exhaustive]
12pub enum BodyType {
13    /// Immovable, infinite mass.
14    Static,
15    /// Affected by forces and collisions.
16    Dynamic,
17    /// Moved by user code, affects dynamic bodies but isn't affected by them.
18    Kinematic,
19}
20
21/// Descriptor for creating a rigid body.
22#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
23pub struct BodyDesc {
24    pub body_type: BodyType,
25    pub position: [f64; 3],
26    pub rotation: f64,
27    #[serde(default)]
28    pub linear_velocity: [f64; 3],
29    #[serde(default)]
30    pub angular_velocity: f64,
31    #[serde(default)]
32    pub linear_damping: f64,
33    #[serde(default)]
34    pub angular_damping: f64,
35    #[serde(default)]
36    pub fixed_rotation: bool,
37    #[serde(default)]
38    pub gravity_scale: Option<f64>,
39}
40
41impl Default for BodyDesc {
42    fn default() -> Self {
43        Self {
44            body_type: BodyType::Dynamic,
45            position: [0.0, 0.0, 0.0],
46            rotation: 0.0,
47            linear_velocity: [0.0, 0.0, 0.0],
48            angular_velocity: 0.0,
49            linear_damping: 0.0,
50            angular_damping: 0.0,
51            fixed_rotation: false,
52            gravity_scale: None,
53        }
54    }
55}
56
57/// Runtime state of a body (read from simulation).
58#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
59pub struct BodyState {
60    pub handle: BodyHandle,
61    pub body_type: BodyType,
62    pub position: [f64; 3],
63    pub rotation: f64,
64    pub linear_velocity: [f64; 3],
65    pub angular_velocity: f64,
66    pub is_sleeping: bool,
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn default_body_desc() {
75        let desc = BodyDesc::default();
76        assert_eq!(desc.body_type, BodyType::Dynamic);
77        assert_eq!(desc.position, [0.0, 0.0, 0.0]);
78        assert_eq!(desc.rotation, 0.0);
79        assert_eq!(desc.linear_damping, 0.0);
80        assert_eq!(desc.angular_damping, 0.0);
81        assert!(!desc.fixed_rotation);
82        assert_eq!(desc.gravity_scale, None);
83    }
84
85    #[test]
86    fn body_desc_serde() {
87        let desc = BodyDesc {
88            body_type: BodyType::Static,
89            position: [5.0, 3.0, 0.0],
90            rotation: 1.57,
91            ..Default::default()
92        };
93        let json = serde_json::to_string(&desc).unwrap();
94        let back: BodyDesc = serde_json::from_str(&json).unwrap();
95        assert_eq!(desc, back);
96    }
97
98    #[test]
99    fn body_desc_kinematic_serde() {
100        let desc = BodyDesc {
101            body_type: BodyType::Kinematic,
102            position: [1.0, 2.0, 0.0],
103            linear_velocity: [3.0, 4.0, 0.0],
104            angular_velocity: 0.5,
105            fixed_rotation: true,
106            gravity_scale: Some(0.5),
107            ..Default::default()
108        };
109        let json = serde_json::to_string(&desc).unwrap();
110        let back: BodyDesc = serde_json::from_str(&json).unwrap();
111        assert_eq!(desc, back);
112    }
113
114    #[test]
115    fn body_handle_eq() {
116        assert_eq!(BodyHandle(1), BodyHandle(1));
117        assert_ne!(BodyHandle(1), BodyHandle(2));
118    }
119
120    #[test]
121    fn body_state_serde() {
122        let state = BodyState {
123            handle: BodyHandle(42),
124            body_type: BodyType::Dynamic,
125            position: [1.0, 2.0, 0.0],
126            rotation: 0.5,
127            linear_velocity: [3.0, 4.0, 0.0],
128            angular_velocity: 1.0,
129            is_sleeping: false,
130        };
131        let json = serde_json::to_string(&state).unwrap();
132        let back: BodyState = serde_json::from_str(&json).unwrap();
133        assert_eq!(state, back);
134    }
135
136    #[test]
137    fn body_state_sleeping() {
138        let state = BodyState {
139            handle: BodyHandle(0),
140            body_type: BodyType::Static,
141            position: [0.0, 0.0, 0.0],
142            rotation: 0.0,
143            linear_velocity: [0.0, 0.0, 0.0],
144            angular_velocity: 0.0,
145            is_sleeping: true,
146        };
147        assert!(state.is_sleeping);
148    }
149}