Skip to main content

dreamwell_engine/physics/
collision.rs

1use serde::{Deserialize, Serialize};
2
3/// Collision detection mode.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
5pub enum CollisionMode {
6    None,
7    Plane,
8    TerrainHeightfield,
9    DepthBuffer,
10    SignedDistanceField,
11    ProxyCollider,
12    VoxelGrid,
13}
14
15/// Collision response behavior.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
17pub enum CollisionResponse {
18    Bounce,
19    Slide,
20    Stick,
21    Die,
22    Split,
23    Shatter,
24    Embed,
25    Sleep,
26    Promote,
27    TriggerSubEmitter,
28}
29
30/// Collision policy for a particle system.
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct CollisionPolicy {
33    pub mode: CollisionMode,
34    pub response: CollisionResponse,
35    pub restitution: f32,
36    pub friction: f32,
37    pub radius: f32,
38    pub max_collisions: u32,
39    pub material_response_table: Option<String>,
40}
41
42impl Default for CollisionPolicy {
43    fn default() -> Self {
44        Self {
45            mode: CollisionMode::None,
46            response: CollisionResponse::Bounce,
47            restitution: 0.5,
48            friction: 0.3,
49            radius: 0.05,
50            max_collisions: 4,
51            material_response_table: None,
52        }
53    }
54}
55
56impl CollisionMode {
57    pub const ALL: &[CollisionMode] = &[
58        Self::None,
59        Self::Plane,
60        Self::TerrainHeightfield,
61        Self::DepthBuffer,
62        Self::SignedDistanceField,
63        Self::ProxyCollider,
64        Self::VoxelGrid,
65    ];
66}
67
68impl CollisionResponse {
69    pub const ALL: &[CollisionResponse] = &[
70        Self::Bounce,
71        Self::Slide,
72        Self::Stick,
73        Self::Die,
74        Self::Split,
75        Self::Shatter,
76        Self::Embed,
77        Self::Sleep,
78        Self::Promote,
79        Self::TriggerSubEmitter,
80    ];
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn collision_mode_all() {
89        assert_eq!(CollisionMode::ALL.len(), 7);
90    }
91
92    #[test]
93    fn collision_response_all() {
94        assert_eq!(CollisionResponse::ALL.len(), 10);
95    }
96
97    #[test]
98    fn collision_policy_default() {
99        let p = CollisionPolicy::default();
100        assert_eq!(p.mode, CollisionMode::None);
101        assert_eq!(p.response, CollisionResponse::Bounce);
102    }
103
104    #[test]
105    fn collision_policy_serde() {
106        let p = CollisionPolicy {
107            mode: CollisionMode::SignedDistanceField,
108            response: CollisionResponse::Slide,
109            restitution: 0.18,
110            friction: 0.82,
111            radius: 0.06,
112            max_collisions: 12,
113            material_response_table: Some("mat/stone".into()),
114        };
115        let json = serde_json::to_string(&p).unwrap();
116        let restored: CollisionPolicy = serde_json::from_str(&json).unwrap();
117        assert_eq!(restored.mode, CollisionMode::SignedDistanceField);
118        assert_eq!(restored.max_collisions, 12);
119    }
120}