boxdd/joints/
motor.rs

1use crate::types::BodyId;
2use crate::world::World;
3use boxdd_sys::ffi;
4
5use super::{Joint, JointBase, JointBaseBuilder, OwnedJoint};
6use crate::error::ApiResult;
7
8// Motor joint
9#[derive(Clone, Debug)]
10/// Motor joint definition (maps to `b2MotorJointDef`). Drives relative motion
11/// between two bodies using linear and angular offsets with configurable
12/// maximum forces.
13pub struct MotorJointDef(pub(crate) ffi::b2MotorJointDef);
14
15impl MotorJointDef {
16    pub fn new(base: JointBase) -> Self {
17        let mut def: ffi::b2MotorJointDef = unsafe { ffi::b2DefaultMotorJointDef() };
18        def.base = base.0;
19        Self(def)
20    }
21    /// Target linear velocity of body B relative to A (m/s).
22    pub fn linear_velocity<V: Into<crate::types::Vec2>>(mut self, v: V) -> Self {
23        self.0.linearVelocity = ffi::b2Vec2::from(v.into());
24        self
25    }
26    /// Maximum force to achieve linear velocity (N).
27    pub fn max_velocity_force(mut self, v: f32) -> Self {
28        self.0.maxVelocityForce = v;
29        self
30    }
31    /// Target angular velocity of body B relative to A (rad/s).
32    pub fn angular_velocity(mut self, v: f32) -> Self {
33        self.0.angularVelocity = v;
34        self
35    }
36    /// Maximum torque to achieve angular velocity (N·m).
37    pub fn max_velocity_torque(mut self, v: f32) -> Self {
38        self.0.maxVelocityTorque = v;
39        self
40    }
41    /// Linear spring stiffness (Hz).
42    pub fn linear_hertz(mut self, v: f32) -> Self {
43        self.0.linearHertz = v;
44        self
45    }
46    /// Linear damping ratio \[0,1].
47    pub fn linear_damping_ratio(mut self, v: f32) -> Self {
48        self.0.linearDampingRatio = v;
49        self
50    }
51    /// Maximum linear spring force (N).
52    pub fn max_spring_force(mut self, v: f32) -> Self {
53        self.0.maxSpringForce = v;
54        self
55    }
56    /// Angular spring stiffness (Hz).
57    pub fn angular_hertz(mut self, v: f32) -> Self {
58        self.0.angularHertz = v;
59        self
60    }
61    /// Angular damping ratio \[0,1].
62    pub fn angular_damping_ratio(mut self, v: f32) -> Self {
63        self.0.angularDampingRatio = v;
64        self
65    }
66    /// Maximum angular spring torque (N·m).
67    pub fn max_spring_torque(mut self, v: f32) -> Self {
68        self.0.maxSpringTorque = v;
69        self
70    }
71}
72
73// Motor joint convenience builder
74/// Fluent builder for motor joints.
75pub struct MotorJointBuilder<'w> {
76    pub(crate) world: &'w mut World,
77    pub(crate) body_a: BodyId,
78    pub(crate) body_b: BodyId,
79    pub(crate) def: MotorJointDef,
80}
81
82impl<'w> MotorJointBuilder<'w> {
83    /// Target linear velocity (m/s).
84    pub fn linear_velocity<V: Into<crate::types::Vec2>>(mut self, v: V) -> Self {
85        self.def = self.def.linear_velocity(ffi::b2Vec2::from(v.into()));
86        self
87    }
88    /// Target angular velocity (rad/s).
89    pub fn angular_velocity(mut self, w: f32) -> Self {
90        self.def = self.def.angular_velocity(w);
91        self
92    }
93    /// Maximum force for achieving linear velocity (N).
94    pub fn max_velocity_force(mut self, f: f32) -> Self {
95        self.def = self.def.max_velocity_force(f);
96        self
97    }
98    /// Maximum torque for achieving angular velocity (N·m).
99    pub fn max_velocity_torque(mut self, t: f32) -> Self {
100        self.def = self.def.max_velocity_torque(t);
101        self
102    }
103    /// Linear spring (Hz, damping ratio).
104    pub fn linear_spring(mut self, hz: f32, dr: f32) -> Self {
105        self.def = self.def.linear_hertz(hz).linear_damping_ratio(dr);
106        self
107    }
108    /// Angular spring (Hz, damping ratio).
109    pub fn angular_spring(mut self, hz: f32, dr: f32) -> Self {
110        self.def = self.def.angular_hertz(hz).angular_damping_ratio(dr);
111        self
112    }
113    /// Allow bodies to collide while connected.
114    pub fn collide_connected(mut self, flag: bool) -> Self {
115        self.def.0.base.collideConnected = flag;
116        self
117    }
118
119    #[must_use]
120    pub fn build(mut self) -> Joint<'w> {
121        crate::core::debug_checks::assert_body_valid(self.body_a);
122        crate::core::debug_checks::assert_body_valid(self.body_b);
123        // Default frames: identity (base only needs bodies)
124        let base = JointBaseBuilder::new()
125            .bodies_by_id(self.body_a, self.body_b)
126            .build();
127        self.def.0.base = base.0;
128        self.world.create_motor_joint(&self.def)
129    }
130
131    pub fn try_build(mut self) -> ApiResult<Joint<'w>> {
132        crate::core::debug_checks::check_body_valid(self.body_a)?;
133        crate::core::debug_checks::check_body_valid(self.body_b)?;
134        let base = JointBaseBuilder::new()
135            .bodies_by_id(self.body_a, self.body_b)
136            .build();
137        self.def.0.base = base.0;
138        self.world.try_create_motor_joint(&self.def)
139    }
140
141    #[must_use]
142    pub fn build_owned(mut self) -> OwnedJoint {
143        crate::core::debug_checks::assert_body_valid(self.body_a);
144        crate::core::debug_checks::assert_body_valid(self.body_b);
145        let base = JointBaseBuilder::new()
146            .bodies_by_id(self.body_a, self.body_b)
147            .build();
148        self.def.0.base = base.0;
149        self.world.create_motor_joint_owned(&self.def)
150    }
151
152    pub fn try_build_owned(mut self) -> ApiResult<OwnedJoint> {
153        crate::core::debug_checks::check_body_valid(self.body_a)?;
154        crate::core::debug_checks::check_body_valid(self.body_b)?;
155        let base = JointBaseBuilder::new()
156            .bodies_by_id(self.body_a, self.body_b)
157            .build();
158        self.def.0.base = base.0;
159        self.world.try_create_motor_joint_owned(&self.def)
160    }
161}