bevy_rapier2d/dynamics/
spring_joint.rs

1use crate::dynamics::{GenericJoint, GenericJointBuilder, JointAxesMask};
2use crate::dynamics::{JointAxis, MotorModel};
3use crate::math::{Real, Vect};
4
5use super::TypedJoint;
6
7#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
8#[derive(Copy, Clone, Debug, PartialEq)]
9#[repr(transparent)]
10/// A spring-damper joint, applies a force proportional to the distance between two objects.
11///
12/// The spring is integrated implicitly, implying that even an undamped spring will be subject to some
13/// amount of numerical damping (so it will eventually come to a rest). More solver iterations, or smaller
14/// timesteps, will lower the effect of numerical damping, providing a more realistic result.
15pub struct SpringJoint {
16    /// The underlying joint data.
17    pub data: GenericJoint,
18}
19
20impl SpringJoint {
21    /// Creates a new spring joint limiting the max distance between two bodies.
22    ///
23    /// The `max_dist` must be strictly greater than 0.0.
24    pub fn new(rest_length: Real, stiffness: Real, damping: Real) -> Self {
25        let data = GenericJointBuilder::new(JointAxesMask::empty())
26            .coupled_axes(JointAxesMask::LIN_AXES)
27            .motor_position(JointAxis::LinX, rest_length, stiffness, damping)
28            .motor_model(JointAxis::LinX, MotorModel::ForceBased)
29            .build();
30        Self { data }
31    }
32
33    /// Are contacts between the attached rigid-bodies enabled?
34    pub fn contacts_enabled(&self) -> bool {
35        self.data.contacts_enabled()
36    }
37
38    /// Sets whether contacts between the attached rigid-bodies are enabled.
39    pub fn set_contacts_enabled(&mut self, enabled: bool) -> &mut Self {
40        self.data.set_contacts_enabled(enabled);
41        self
42    }
43
44    /// The joint’s anchor, expressed in the local-space of the first rigid-body.
45    #[must_use]
46    pub fn local_anchor1(&self) -> Vect {
47        self.data.local_anchor1()
48    }
49
50    /// Sets the joint’s anchor, expressed in the local-space of the first rigid-body.
51    pub fn set_local_anchor1(&mut self, anchor1: Vect) -> &mut Self {
52        self.data.set_local_anchor1(anchor1);
53        self
54    }
55
56    /// The joint’s anchor, expressed in the local-space of the second rigid-body.
57    #[must_use]
58    pub fn local_anchor2(&self) -> Vect {
59        self.data.local_anchor2()
60    }
61
62    /// Sets the joint’s anchor, expressed in the local-space of the second rigid-body.
63    pub fn set_local_anchor2(&mut self, anchor2: Vect) -> &mut Self {
64        self.data.set_local_anchor2(anchor2);
65        self
66    }
67
68    /// Set the spring model used by this joint to reach the desired target velocity and position.
69    ///
70    /// Setting this to `MotorModel::ForceBased` (which is the default value for this joint) makes the spring constants
71    /// (stiffness and damping) parameter understood as in the regular spring-mass-damper system. With
72    /// `MotorModel::AccelerationBased`, the spring constants will be automatically scaled by the attached masses,
73    /// making the spring more mass-independent.
74    pub fn set_spring_model(&mut self, model: MotorModel) -> &mut Self {
75        self.data.set_motor_model(JointAxis::LinX, model);
76        self
77    }
78}
79
80impl From<SpringJoint> for GenericJoint {
81    fn from(val: SpringJoint) -> GenericJoint {
82        val.data
83    }
84}
85
86/// A [SpringJoint] joint using the builder pattern.
87///
88/// This builds a spring-damper joint which applies a force proportional to the distance between two objects.
89/// See the documentation of [SpringJoint] for more information on its behavior.
90#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
91#[derive(Copy, Clone, Debug, PartialEq)]
92pub struct SpringJointBuilder(pub SpringJoint);
93
94impl SpringJointBuilder {
95    /// Creates a new builder for spring joints.
96    ///
97    /// This axis is expressed in the local-space of both rigid-bodies.
98    pub fn new(rest_length: Real, stiffness: Real, damping: Real) -> Self {
99        Self(SpringJoint::new(rest_length, stiffness, damping))
100    }
101
102    /// Sets whether contacts between the attached rigid-bodies are enabled.
103    #[must_use]
104    pub fn contacts_enabled(mut self, enabled: bool) -> Self {
105        self.0.set_contacts_enabled(enabled);
106        self
107    }
108
109    /// Sets the joint’s anchor, expressed in the local-space of the first rigid-body.
110    #[must_use]
111    pub fn local_anchor1(mut self, anchor1: Vect) -> Self {
112        self.0.set_local_anchor1(anchor1);
113        self
114    }
115
116    /// Sets the joint’s anchor, expressed in the local-space of the second rigid-body.
117    #[must_use]
118    pub fn local_anchor2(mut self, anchor2: Vect) -> Self {
119        self.0.set_local_anchor2(anchor2);
120        self
121    }
122
123    /// Set the spring used by this joint to reach the desired target velocity and position.
124    ///
125    /// Setting this to `MotorModel::ForceBased` (which is the default value for this joint) makes the spring constants
126    /// (stiffness and damping) parameter understood as in the regular spring-mass-damper system. With
127    /// `MotorModel::AccelerationBased`, the spring constants will be automatically scaled by the attached masses,
128    /// making the spring more mass-independent.
129    #[must_use]
130    pub fn spring_model(mut self, model: MotorModel) -> Self {
131        self.0.set_spring_model(model);
132        self
133    }
134
135    /// Builds the spring joint.
136    #[must_use]
137    pub fn build(self) -> SpringJoint {
138        self.0
139    }
140}
141
142impl From<SpringJointBuilder> for TypedJoint {
143    fn from(joint: SpringJointBuilder) -> TypedJoint {
144        joint.0.into()
145    }
146}
147
148impl From<SpringJoint> for TypedJoint {
149    fn from(joint: SpringJoint) -> TypedJoint {
150        TypedJoint::SpringJoint(joint)
151    }
152}