Skip to main content

concinnity_core/physics/sim/character/
capsule.rs

1// The capsule a character move is resolved against, held by the caller across
2// the fixed ticks rather than rebuilt per move. Here that cache buys nothing --
3// the shape is two floats and building one allocates nothing -- but the shape
4// is the one thing a simulation genuinely owns, so it is the caller that keeps
5// it and a simulation whose shape does cost something needs no other change.
6
7use crate::physics::ColliderShape;
8
9/// A character's collision capsule: a cylinder of `2 * half_height` capped by
10/// hemispheres of `radius`, standing on the y axis.
11#[derive(Debug, Clone, Copy, PartialEq)]
12pub struct CharacterCapsule {
13    half_height: f32,
14    radius: f32,
15}
16
17impl CharacterCapsule {
18    /// Build the capsule for a cylinder of `2 * half_height` capped by
19    /// hemispheres of `radius`.
20    pub fn new(half_height: f32, radius: f32) -> Self {
21        CharacterCapsule {
22            half_height,
23            radius,
24        }
25    }
26
27    /// Adopt new dimensions, for a character whose capsule was re-authored.
28    pub fn resize(&mut self, half_height: f32, radius: f32) {
29        self.half_height = half_height;
30        self.radius = radius;
31    }
32
33    /// Half the cylindrical section's height, excluding the caps.
34    pub fn half_height(&self) -> f32 {
35        self.half_height
36    }
37
38    /// Cap and cylinder radius.
39    pub fn radius(&self) -> f32 {
40        self.radius
41    }
42
43    /// The capsule as a collider shape, which is what a sweep is asked in
44    /// terms of.
45    pub(crate) fn shape(&self) -> ColliderShape {
46        ColliderShape::Capsule {
47            half_height: self.half_height,
48            radius: self.radius,
49        }
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn the_capsule_carries_the_dimensions_it_was_built_from() {
59        let capsule = CharacterCapsule::new(0.6, 0.3);
60        assert_eq!(capsule.half_height(), 0.6);
61        assert_eq!(capsule.radius(), 0.3);
62        assert_eq!(
63            capsule.shape(),
64            ColliderShape::Capsule {
65                half_height: 0.6,
66                radius: 0.3,
67            }
68        );
69    }
70
71    #[test]
72    fn resizing_replaces_both_dimensions() {
73        let mut capsule = CharacterCapsule::new(0.6, 0.3);
74        capsule.resize(0.6, 0.3);
75        assert_eq!(capsule, CharacterCapsule::new(0.6, 0.3));
76        capsule.resize(0.9, 0.4);
77        assert_eq!(capsule.half_height(), 0.9);
78        assert_eq!(capsule.radius(), 0.4);
79    }
80}