Something went wrong. Try again.
Homebrew 4D Game Engine In Rust, inspired by Engine4D
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153//! Physical material properties for collision response
/// Physical material properties for collision response////// Materials define how objects interact during collisions, including/// friction (how much objects resist sliding) and restitution (bounciness).#[derive(Clone, Copy, Debug, PartialEq)]pub struct PhysicsMaterial { /// Friction coefficient (0.0 = ice, 1.0 = rubber) pub friction: f32, /// Restitution/bounciness (0.0 = no bounce, 1.0 = perfect bounce) pub restitution: f32,}
impl Default for PhysicsMaterial { fn default() -> Self { Self { friction: 0.5, restitution: 0.0, } }}
impl PhysicsMaterial { /// Ice-like material: very low friction, slight bounce pub const ICE: Self = Self { friction: 0.05, restitution: 0.1, };
/// Rubber-like material: high friction, very bouncy pub const RUBBER: Self = Self { friction: 0.9, restitution: 0.8, };
/// Metal-like material: moderate friction and bounce pub const METAL: Self = Self { friction: 0.3, restitution: 0.3, };
/// Wood-like material: moderate friction, low bounce pub const WOOD: Self = Self { friction: 0.5, restitution: 0.2, };
/// Concrete-like material: high friction, very low bounce pub const CONCRETE: Self = Self { friction: 0.7, restitution: 0.1, };
/// Create a new physics material with custom friction and restitution /// /// Values are clamped to the range [0.0, 1.0]. pub fn new(friction: f32, restitution: f32) -> Self { Self { friction: friction.clamp(0.0, 1.0), restitution: restitution.clamp(0.0, 1.0), } }
/// Combine two materials for collision response /// /// Uses geometric mean for friction (models surface interaction well) /// and maximum for restitution (most bouncy surface wins). pub fn combine(&self, other: &Self) -> Self { Self { friction: (self.friction * other.friction).sqrt(), restitution: self.restitution.max(other.restitution), } }}
#[cfg(test)]mod tests { use super::*;
#[test] fn test_default_material() { let material = PhysicsMaterial::default(); assert_eq!(material.friction, 0.5); assert_eq!(material.restitution, 0.0); }
#[test] fn test_new_clamps_values() { let material = PhysicsMaterial::new(1.5, -0.5); assert_eq!(material.friction, 1.0); assert_eq!(material.restitution, 0.0);
let material = PhysicsMaterial::new(-1.0, 2.0); assert_eq!(material.friction, 0.0); assert_eq!(material.restitution, 1.0); }
#[test] #[allow(clippy::assertions_on_constants)] // deliberate sanity checks on preset values fn test_preset_constants() { // Test that presets have expected properties assert!(PhysicsMaterial::ICE.friction < 0.1); assert!(PhysicsMaterial::RUBBER.friction > 0.8); assert!(PhysicsMaterial::RUBBER.restitution > 0.7); assert!(PhysicsMaterial::CONCRETE.friction > 0.6); assert!(PhysicsMaterial::CONCRETE.restitution < 0.2); }
#[test] fn test_combine_geometric_mean_friction() { let ice = PhysicsMaterial::ICE; let rubber = PhysicsMaterial::RUBBER; let combined = ice.combine(&rubber);
// Geometric mean of 0.05 and 0.9 = sqrt(0.045) ≈ 0.212 let expected_friction = (0.05_f32 * 0.9_f32).sqrt(); assert!((combined.friction - expected_friction).abs() < 0.0001); }
#[test] fn test_combine_max_restitution() { let metal = PhysicsMaterial::METAL; // restitution 0.3 let rubber = PhysicsMaterial::RUBBER; // restitution 0.8 let combined = metal.combine(&rubber);
// Max of 0.3 and 0.8 = 0.8 assert_eq!(combined.restitution, 0.8); }
#[test] fn test_combine_is_commutative() { let a = PhysicsMaterial::new(0.3, 0.5); let b = PhysicsMaterial::new(0.7, 0.2);
let ab = a.combine(&b); let ba = b.combine(&a);
assert!((ab.friction - ba.friction).abs() < 0.0001); assert_eq!(ab.restitution, ba.restitution); }
#[test] fn test_combine_same_material() { let material = PhysicsMaterial::new(0.5, 0.3); let combined = material.combine(&material);
// sqrt(0.5 * 0.5) = 0.5 assert_eq!(combined.friction, 0.5); assert_eq!(combined.restitution, 0.3); }}