concinnity_asset/
prop_body.rs1use crate::{AssetId, AudioClipHandle, de_opt_asset_ref, de_opt_audio_clip_handle};
4
5#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
20#[serde(default)]
21pub struct PropBody {
22 #[serde(deserialize_with = "de_opt_asset_ref")]
25 pub prop_name: Option<AssetId>,
26 pub mass: f32,
29 pub friction: f32,
31 pub restitution: f32,
33 pub gravity_scale: f32,
35 pub linear_damping: f32,
37 #[serde(deserialize_with = "de_opt_audio_clip_handle")]
41 pub impact_clip: Option<AudioClipHandle>,
42 pub impact_volume: f32,
44}
45
46impl Default for PropBody {
47 fn default() -> Self {
48 Self {
49 prop_name: None,
50 mass: 0.0,
51 friction: 0.5,
52 restitution: 0.0,
53 gravity_scale: 1.0,
54 linear_damping: 0.05,
55 impact_clip: None,
56 impact_volume: 1.0,
57 }
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn a_blank_body_falls_under_full_gravity_without_bouncing() {
67 let b = PropBody::default();
68 assert_eq!(b.gravity_scale, 1.0);
69 assert_eq!(b.friction, 0.5);
70 assert_eq!(b.restitution, 0.0);
71 assert_eq!(b.linear_damping, 0.05);
72 assert_eq!(b.mass, 0.0);
74 assert!(b.prop_name.is_none());
75 }
76
77 #[test]
78 fn a_bouncy_floating_body_parses_and_round_trips_through_postcard() {
79 crate::test_support::install_resolvers();
80 let b: PropBody = serde_json::from_str(
81 r#"{"prop_name":"ball","mass":2.5,"friction":0.1,"restitution":0.9,
82 "gravity_scale":0,"linear_damping":0.2}"#,
83 )
84 .unwrap();
85 assert_eq!(b.prop_name, Some(AssetId(4)));
86 assert_eq!(b.gravity_scale, 0.0);
87
88 let bytes = postcard::to_allocvec(&b).unwrap();
89 let back: PropBody = postcard::from_bytes(&bytes).unwrap();
90 assert_eq!(back.prop_name, Some(AssetId(4)));
91 assert_eq!(back.mass, 2.5);
92 assert_eq!(back.friction, 0.1);
93 assert_eq!(back.restitution, 0.9);
94 assert_eq!(back.linear_damping, 0.2);
95 }
96}