use crate::material::PhysicsMaterial;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct ColliderHandle(pub u64);
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum ColliderShape {
Box { half_extents: [f64; 3] },
Ball { radius: f64 },
Capsule { half_height: f64, radius: f64 },
ConvexHull { points: Vec<[f64; 3]> },
TriMesh {
vertices: Vec<[f64; 3]>,
indices: Vec<[u32; 3]>,
},
Heightfield { heights: Vec<f64>, scale: [f64; 3] },
Segment { a: [f64; 3], b: [f64; 3] },
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ColliderDesc {
pub shape: ColliderShape,
#[serde(default)]
pub offset: [f64; 3],
#[serde(default)]
pub material: PhysicsMaterial,
#[serde(default)]
pub is_sensor: bool,
#[serde(default)]
pub mass: Option<f64>,
#[serde(default = "default_layer")]
pub collision_layer: u32,
#[serde(default = "default_mask")]
pub collision_mask: u32,
}
fn default_layer() -> u32 {
0xFFFF_FFFF
}
fn default_mask() -> u32 {
0xFFFF_FFFF
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn collider_shapes_serde() {
let shapes = vec![
ColliderShape::Box {
half_extents: [1.0, 1.0, 0.0],
},
ColliderShape::Ball { radius: 0.5 },
ColliderShape::Capsule {
half_height: 1.0,
radius: 0.3,
},
];
for shape in &shapes {
let json = serde_json::to_string(shape).unwrap();
let back: ColliderShape = serde_json::from_str(&json).unwrap();
assert_eq!(shape, &back);
}
}
#[test]
fn convex_hull_serde() {
let shape = ColliderShape::ConvexHull {
points: vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.5, 1.0, 0.0]],
};
let json = serde_json::to_string(&shape).unwrap();
let back: ColliderShape = serde_json::from_str(&json).unwrap();
assert_eq!(shape, back);
}
#[test]
fn trimesh_serde() {
let shape = ColliderShape::TriMesh {
vertices: vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
indices: vec![[0, 1, 2]],
};
let json = serde_json::to_string(&shape).unwrap();
let back: ColliderShape = serde_json::from_str(&json).unwrap();
assert_eq!(shape, back);
}
#[test]
fn heightfield_serde() {
let shape = ColliderShape::Heightfield {
heights: vec![0.0, 1.0, 0.5, 2.0],
scale: [1.0, 1.0, 0.0],
};
let json = serde_json::to_string(&shape).unwrap();
let back: ColliderShape = serde_json::from_str(&json).unwrap();
assert_eq!(shape, back);
}
#[test]
fn segment_serde() {
let shape = ColliderShape::Segment {
a: [0.0, 0.0, 0.0],
b: [5.0, 5.0, 0.0],
};
let json = serde_json::to_string(&shape).unwrap();
let back: ColliderShape = serde_json::from_str(&json).unwrap();
assert_eq!(shape, back);
}
#[test]
fn sensor_collider() {
let desc = ColliderDesc {
shape: ColliderShape::Ball { radius: 5.0 },
offset: [0.0, 0.0, 0.0],
material: PhysicsMaterial::default(),
is_sensor: true,
mass: None,
collision_layer: 0xFFFF_FFFF,
collision_mask: 0xFFFF_FFFF,
};
assert!(desc.is_sensor);
}
#[test]
fn collider_desc_serde() {
let desc = ColliderDesc {
shape: ColliderShape::Box {
half_extents: [2.0, 3.0, 0.0],
},
offset: [1.0, 1.0, 0.0],
material: PhysicsMaterial::steel(),
is_sensor: false,
mass: Some(10.0),
collision_layer: 0xFFFF_FFFF,
collision_mask: 0xFFFF_FFFF,
};
let json = serde_json::to_string(&desc).unwrap();
let back: ColliderDesc = serde_json::from_str(&json).unwrap();
assert_eq!(desc, back);
}
}