From 0078278943d856b06aea2e3cc10a20b5bd1ed7b2 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Mon, 17 Jun 2024 15:34:37 +0200 Subject: [PATCH] exploration for removing code duplication between rapier and bevy_rapier --- bevy_rapier2d/examples/debug_despawn2.rs | 11 +- bevy_rapier2d/examples/joints2.rs | 11 +- bevy_rapier2d/examples/joints_despawn2.rs | 12 +- bevy_rapier3d/examples/joints3.rs | 23 ++- bevy_rapier3d/examples/joints_despawn3.rs | 17 +- src/dynamics/generic_joint.rs | 6 + src/dynamics/revolute_joint.rs | 227 +++++----------------- 7 files changed, 96 insertions(+), 211 deletions(-) diff --git a/bevy_rapier2d/examples/debug_despawn2.rs b/bevy_rapier2d/examples/debug_despawn2.rs index 8fc57af69..4e2261648 100644 --- a/bevy_rapier2d/examples/debug_despawn2.rs +++ b/bevy_rapier2d/examples/debug_despawn2.rs @@ -3,7 +3,9 @@ // in https://github.com/dimforge/bevy_rapier/issues/75 use bevy::prelude::*; +use bevy_rapier2d::dynamics::RevoluteJointBuilderGlam; use bevy_rapier2d::prelude::*; +use rapier2d::dynamics::RevoluteJointBuilder; fn main() { App::new() @@ -172,10 +174,11 @@ fn spawn_cube(commands: &mut Commands, game: &mut Game) { let id = children .spawn(ImpulseJoint::new( block_entities[*i], - RevoluteJointBuilder::new() - .local_anchor1(anchor_1) - .local_anchor2(anchor_2) - .build(), + RevoluteJointBuilder::new_glam() + .local_anchor1_glam(anchor_1) + .local_anchor2_glam(anchor_2) + .build() + .data, )) .id(); game.current_cube_joints.push(id); diff --git a/bevy_rapier2d/examples/joints2.rs b/bevy_rapier2d/examples/joints2.rs index e30352ca6..f79a26e1f 100644 --- a/bevy_rapier2d/examples/joints2.rs +++ b/bevy_rapier2d/examples/joints2.rs @@ -1,5 +1,6 @@ use bevy::prelude::*; use bevy_rapier2d::prelude::*; +use rapier2d::dynamics::RevoluteJointBuilder; fn main() { App::new() @@ -55,12 +56,13 @@ pub fn setup_physics(mut commands: Commands) { // Vertical joint. if i > 0 { let parent_entity = *body_entities.last().unwrap(); - let joint = RevoluteJointBuilder::new().local_anchor2(Vec2::new(0.0, shift)); + let joint = + RevoluteJointBuilder::new_glam().local_anchor2_glam(Vec2::new(0.0, shift)); commands.entity(child_entity).with_children(|cmd| { // NOTE: we want to attach multiple impulse joints to this entity, so // we need to add the components to children of the entity. Otherwise // the second joint component would just overwrite the first one. - cmd.spawn(ImpulseJoint::new(parent_entity, joint)); + cmd.spawn(ImpulseJoint::new(parent_entity, joint.build().data)); }); } @@ -68,12 +70,13 @@ pub fn setup_physics(mut commands: Commands) { if k > 0 { let parent_index = body_entities.len() - numi; let parent_entity = body_entities[parent_index]; - let joint = RevoluteJointBuilder::new().local_anchor2(Vec2::new(-shift, 0.0)); + let joint = + RevoluteJointBuilder::new_glam().local_anchor2_glam(Vec2::new(-shift, 0.0)); commands.entity(child_entity).with_children(|cmd| { // NOTE: we want to attach multiple impulse joints to this entity, so // we need to add the components to children of the entity. Otherwise // the second joint component would just overwrite the first one. - cmd.spawn(ImpulseJoint::new(parent_entity, joint)); + cmd.spawn(ImpulseJoint::new(parent_entity, joint.build().data)); }); } diff --git a/bevy_rapier2d/examples/joints_despawn2.rs b/bevy_rapier2d/examples/joints_despawn2.rs index 736d868b6..c5fc33396 100644 --- a/bevy_rapier2d/examples/joints_despawn2.rs +++ b/bevy_rapier2d/examples/joints_despawn2.rs @@ -1,5 +1,6 @@ use bevy::prelude::*; use bevy_rapier2d::prelude::*; +use rapier2d::dynamics::RevoluteJointBuilder; #[derive(Component, Default)] pub struct Despawn; @@ -67,12 +68,14 @@ pub fn setup_physics(mut commands: Commands, mut despawn: ResMut 0 { let parent_entity = *body_entities.last().unwrap(); - let joint = RevoluteJointBuilder::new().local_anchor2(Vec2::new(0.0, shift)); + let joint = + RevoluteJointBuilder::new_glam().local_anchor2_glam(Vec2::new(0.0, shift)); commands.entity(child_entity).with_children(|cmd| { // NOTE: we want to attach multiple impulse joints to this entity, so // we need to add the components to children of the entity. Otherwise // the second joint component would just overwrite the first one. - let mut entity = cmd.spawn(ImpulseJoint::new(parent_entity, joint)); + let mut entity = + cmd.spawn(ImpulseJoint::new(parent_entity, joint.build().data)); if i == (numi / 2) || (k % 4 == 0 || k == numk - 1) { entity.insert(Despawn); } @@ -83,12 +86,13 @@ pub fn setup_physics(mut commands: Commands, mut despawn: ResMut 0 { let parent_index = body_entities.len() - numi; let parent_entity = body_entities[parent_index]; - let joint = RevoluteJointBuilder::new().local_anchor2(Vec2::new(-shift, 0.0)); + let joint = RevoluteJointBuilder::new().local_anchor2_glam(Vec2::new(-shift, 0.0)); commands.entity(child_entity).with_children(|cmd| { // NOTE: we want to attach multiple impulse joints to this entity, so // we need to add the components to children of the entity. Otherwise // the second joint component would just overwrite the first one. - let mut entity = cmd.spawn(ImpulseJoint::new(parent_entity, joint)); + let mut entity = + cmd.spawn(ImpulseJoint::new(parent_entity, joint.build().data)); if i == (numi / 2) || (k % 4 == 0 || k == numk - 1) { entity.insert(Despawn); } diff --git a/bevy_rapier3d/examples/joints3.rs b/bevy_rapier3d/examples/joints3.rs index 52f35e961..d77fb6ca9 100644 --- a/bevy_rapier3d/examples/joints3.rs +++ b/bevy_rapier3d/examples/joints3.rs @@ -1,5 +1,9 @@ use bevy::prelude::*; use bevy_rapier3d::prelude::*; +use rapier3d::dynamics::RevoluteJointBuilder; + +use bevy_rapier3d::dynamics::RevoluteJointBuilderGlam; +//use rapier3d::dynamics::RevoluteJointBuilder; fn main() { App::new() @@ -128,25 +132,26 @@ fn create_revolute_joints(commands: &mut Commands, origin: Vec3, num: usize) { let x = Vec3::X; let z = Vec3::Z; - let revs = [ - RevoluteJointBuilder::new(z).local_anchor2(Vec3::new(0.0, 0.0, -shift)), - RevoluteJointBuilder::new(x).local_anchor2(Vec3::new(-shift, 0.0, 0.0)), - RevoluteJointBuilder::new(z).local_anchor2(Vec3::new(0.0, 0.0, -shift)), - RevoluteJointBuilder::new(x).local_anchor2(Vec3::new(shift, 0.0, 0.0)), + let revs: [RevoluteJointBuilder; 4] = [ + RevoluteJointBuilder::new_glam(z).local_anchor2_glam(Vec3::new(0.0, 0.0, -shift)), + RevoluteJointBuilder::new_glam(x).local_anchor2_glam(Vec3::new(-shift, 0.0, 0.0)), + RevoluteJointBuilder::new_glam(z).local_anchor2_glam(Vec3::new(0.0, 0.0, -shift)), + RevoluteJointBuilder::new_glam(x).local_anchor2_glam(Vec3::new(shift, 0.0, 0.0)), ]; + let joint = ImpulseJoint::new(curr_parent, revs[0].build().data); commands .entity(handles[0]) - .insert(ImpulseJoint::new(curr_parent, revs[0])); + .insert(ImpulseJoint::new(curr_parent, revs[0].build().data)); commands .entity(handles[1]) - .insert(ImpulseJoint::new(handles[0], revs[1])); + .insert(ImpulseJoint::new(handles[0], revs[1].build().data)); commands .entity(handles[2]) - .insert(ImpulseJoint::new(handles[1], revs[2])); + .insert(ImpulseJoint::new(handles[1], revs[2].build().data)); commands .entity(handles[3]) - .insert(ImpulseJoint::new(handles[2], revs[3])); + .insert(ImpulseJoint::new(handles[2], revs[3].build().data)); curr_parent = handles[3]; } diff --git a/bevy_rapier3d/examples/joints_despawn3.rs b/bevy_rapier3d/examples/joints_despawn3.rs index 17d1608f4..74b0190dc 100644 --- a/bevy_rapier3d/examples/joints_despawn3.rs +++ b/bevy_rapier3d/examples/joints_despawn3.rs @@ -1,5 +1,6 @@ use bevy::prelude::*; use bevy_rapier3d::prelude::*; +use rapier3d::dynamics::RevoluteJointBuilder; #[derive(Component)] pub struct Despawn; @@ -116,24 +117,24 @@ fn create_revolute_joints(commands: &mut Commands, origin: Vec3, num: usize) { let z = Vec3::Z; let revs = [ - RevoluteJointBuilder::new(z).local_anchor2(Vec3::new(0.0, 0.0, -shift)), - RevoluteJointBuilder::new(x).local_anchor2(Vec3::new(-shift, 0.0, 0.0)), - RevoluteJointBuilder::new(z).local_anchor2(Vec3::new(0.0, 0.0, -shift)), - RevoluteJointBuilder::new(x).local_anchor2(Vec3::new(shift, 0.0, 0.0)), + RevoluteJointBuilder::new_glam(z).local_anchor2_glam(Vec3::new(0.0, 0.0, -shift)), + RevoluteJointBuilder::new_glam(x).local_anchor2_glam(Vec3::new(-shift, 0.0, 0.0)), + RevoluteJointBuilder::new_glam(z).local_anchor2_glam(Vec3::new(0.0, 0.0, -shift)), + RevoluteJointBuilder::new_glam(x).local_anchor2_glam(Vec3::new(shift, 0.0, 0.0)), ]; commands .entity(handles[0]) - .insert(ImpulseJoint::new(curr_parent, revs[0])); + .insert(ImpulseJoint::new(curr_parent, revs[0].build().data)); commands .entity(handles[1]) - .insert(ImpulseJoint::new(handles[0], revs[1])); + .insert(ImpulseJoint::new(handles[0], revs[1].build().data)); commands .entity(handles[2]) - .insert(ImpulseJoint::new(handles[1], revs[2])); + .insert(ImpulseJoint::new(handles[1], revs[2].build().data)); commands .entity(handles[3]) - .insert(ImpulseJoint::new(handles[2], revs[3])); + .insert(ImpulseJoint::new(handles[2], revs[3].build().data)); curr_parent = handles[3]; diff --git a/src/dynamics/generic_joint.rs b/src/dynamics/generic_joint.rs index 833dbc722..c658ddf69 100644 --- a/src/dynamics/generic_joint.rs +++ b/src/dynamics/generic_joint.rs @@ -24,6 +24,12 @@ impl GenericJoint { } } +impl From for GenericJoint { + fn from(joint: RapierGenericJoint) -> GenericJoint { + Self { raw: joint } + } +} + /* * NOTE: the following are copy-pasted from Rapier’s GenericJoint, to match its * construction methods, but using glam types. diff --git a/src/dynamics/revolute_joint.rs b/src/dynamics/revolute_joint.rs index 590c033ca..aa84d2756 100644 --- a/src/dynamics/revolute_joint.rs +++ b/src/dynamics/revolute_joint.rs @@ -1,27 +1,30 @@ -use crate::dynamics::{GenericJoint, GenericJointBuilder}; -use crate::math::{Real, Vect}; -use rapier::dynamics::{JointAxesMask, JointAxis, JointLimits, JointMotor, MotorModel}; +//use crate::dynamics::{GenericJoint, GenericJointBuilder}; +use crate::math::Vect; +use rapier::prelude::{GenericJoint, RevoluteJoint as RapierRevoluteJoint, RevoluteJointBuilder}; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, PartialEq)] #[repr(transparent)] -/// A revolute joint, locks all relative motion except for rotation along the joint’s principal axis. +/// Wrapper for rapier's [`RapierRevoluteJoint`], allowing to add more methods compatible with glam. +/// +/// For more info see [`RapierRevoluteJoint`]. pub struct RevoluteJoint { - data: GenericJoint, + /// Inner data from rapier. + pub data: RapierRevoluteJoint, } #[cfg(feature = "dim2")] impl Default for RevoluteJoint { fn default() -> Self { - Self::new() + Self::new_glam() } } impl RevoluteJoint { /// Creates a new revolute joint allowing only relative rotations. #[cfg(feature = "dim2")] - pub fn new() -> Self { - let data = GenericJointBuilder::new(JointAxesMask::LOCKED_REVOLUTE_AXES); + pub fn new_glam() -> Self { + let data = RevoluteJointBuilder::new(); Self { data: data.build() } } @@ -29,223 +32,83 @@ impl RevoluteJoint { /// /// This axis is expressed in the local-space of both rigid-bodies. #[cfg(feature = "dim3")] - pub fn new(axis: Vect) -> Self { - let data = GenericJointBuilder::new(JointAxesMask::LOCKED_REVOLUTE_AXES) - .local_axis1(axis) - .local_axis2(axis) - .build(); + pub fn new_glam(axis: Vect) -> Self { + use rapier::math::UnitVector; + let vector = UnitVector::::new_normalize(axis.into()); + let data = RevoluteJointBuilder::new(vector).build(); Self { data } } - /// The underlying generic joint. - pub fn data(&self) -> &GenericJoint { - &self.data - } - - /// Are contacts between the attached rigid-bodies enabled? - pub fn contacts_enabled(&self) -> bool { - self.data.contacts_enabled() - } - - /// Sets whether contacts between the attached rigid-bodies are enabled. - pub fn set_contacts_enabled(&mut self, enabled: bool) -> &mut Self { - self.data.set_contacts_enabled(enabled); - self - } - /// The joint’s anchor, expressed in the local-space of the first rigid-body. #[must_use] - pub fn local_anchor1(&self) -> Vect { - self.data.local_anchor1() + pub fn local_anchor1_glam(&self) -> Vect { + self.data.local_anchor1().into() } /// Sets the joint’s anchor, expressed in the local-space of the first rigid-body. - pub fn set_local_anchor1(&mut self, anchor1: Vect) -> &mut Self { - self.data.set_local_anchor1(anchor1); + pub fn set_local_anchor1_glam(&mut self, anchor1: Vect) -> &mut Self { + self.data.set_local_anchor1(anchor1.into()); self } /// The joint’s anchor, expressed in the local-space of the second rigid-body. #[must_use] - pub fn local_anchor2(&self) -> Vect { - self.data.local_anchor2() + pub fn local_anchor2_glam(&self) -> Vect { + self.data.local_anchor2().into() } /// Sets the joint’s anchor, expressed in the local-space of the second rigid-body. - pub fn set_local_anchor2(&mut self, anchor2: Vect) -> &mut Self { - self.data.set_local_anchor2(anchor2); - self - } - - /// The motor affecting the joint’s rotational degree of freedom. - #[must_use] - pub fn motor(&self) -> Option<&JointMotor> { - self.data.motor(JointAxis::AngX) - } - - /// Set the spring-like model used by the motor to reach the desired target velocity and position. - pub fn set_motor_model(&mut self, model: MotorModel) -> &mut Self { - self.data.set_motor_model(JointAxis::AngX, model); - self - } - - /// Sets the target velocity this motor needs to reach. - pub fn set_motor_velocity(&mut self, target_vel: Real, factor: Real) -> &mut Self { - self.data - .set_motor_velocity(JointAxis::AngX, target_vel, factor); - self - } - - /// Sets the target angle this motor needs to reach. - pub fn set_motor_position( - &mut self, - target_pos: Real, - stiffness: Real, - damping: Real, - ) -> &mut Self { - self.data - .set_motor_position(JointAxis::AngX, target_pos, stiffness, damping); - self - } - - /// Configure both the target angle and target velocity of the motor. - pub fn set_motor( - &mut self, - target_pos: Real, - target_vel: Real, - stiffness: Real, - damping: Real, - ) -> &mut Self { - self.data - .set_motor(JointAxis::AngX, target_pos, target_vel, stiffness, damping); - self - } - - /// Sets the maximum force the motor can deliver. - pub fn set_motor_max_force(&mut self, max_force: Real) -> &mut Self { - self.data.set_motor_max_force(JointAxis::AngX, max_force); - self - } - - /// The limit angle attached bodies can translate along the joint’s principal axis. - #[must_use] - pub fn limits(&self) -> Option<&JointLimits> { - self.data.limits(JointAxis::AngX) - } - - /// Sets the `[min,max]` limit angle attached bodies can translate along the joint’s principal axis. - pub fn set_limits(&mut self, limits: [Real; 2]) -> &mut Self { - self.data.set_limits(JointAxis::AngX, limits); + pub fn set_local_anchor2_glam(&mut self, anchor2: Vect) -> &mut Self { + self.data.set_local_anchor2(anchor2.into()); self } } impl From for GenericJoint { fn from(joint: RevoluteJoint) -> GenericJoint { - joint.data + joint.data.data } } -/// Create revolute joints using the builder pattern. -/// -/// A revolute joint locks all relative motion except for rotations along the joint’s principal axis. -#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct RevoluteJointBuilder(RevoluteJoint); - -#[cfg(feature = "dim2")] -impl Default for RevoluteJointBuilder { - fn default() -> Self { - Self::new() - } -} - -impl RevoluteJointBuilder { - /// Creates a new revolute joint builder. +/// A trait to extend [`rapier::prelude::RevoluteJointBuilder`] with glam types. +pub trait RevoluteJointBuilderGlam { + /// Creates a new revolute joint allowing only relative rotations. #[cfg(feature = "dim2")] - pub fn new() -> Self { - Self(RevoluteJoint::new()) - } + fn new_glam() -> Self; /// Creates a new revolute joint builder, allowing only relative rotations along the specified axis. /// /// This axis is expressed in the local-space of both rigid-bodies. #[cfg(feature = "dim3")] - pub fn new(axis: Vect) -> Self { - Self(RevoluteJoint::new(axis)) - } + fn new_glam(axis: Vect) -> Self; /// Sets the joint’s anchor, expressed in the local-space of the first rigid-body. - #[must_use] - pub fn local_anchor1(mut self, anchor1: Vect) -> Self { - self.0.set_local_anchor1(anchor1); - self - } + fn local_anchor1_glam(self: Self, anchor1: Vect) -> Self; /// Sets the joint’s anchor, expressed in the local-space of the second rigid-body. - #[must_use] - pub fn local_anchor2(mut self, anchor2: Vect) -> Self { - self.0.set_local_anchor2(anchor2); - self - } - - /// Set the spring-like model used by the motor to reach the desired target velocity and position. - #[must_use] - pub fn motor_model(mut self, model: MotorModel) -> Self { - self.0.set_motor_model(model); - self - } - - /// Sets the target velocity this motor needs to reach. - #[must_use] - pub fn motor_velocity(mut self, target_vel: Real, factor: Real) -> Self { - self.0.set_motor_velocity(target_vel, factor); - self - } - - /// Sets the target angle this motor needs to reach. - #[must_use] - pub fn motor_position(mut self, target_pos: Real, stiffness: Real, damping: Real) -> Self { - self.0.set_motor_position(target_pos, stiffness, damping); - self - } + fn local_anchor2_glam(self: Self, anchor2: Vect) -> Self; +} - /// Configure both the target angle and target velocity of the motor. - #[must_use] - pub fn motor( - mut self, - target_pos: Real, - target_vel: Real, - stiffness: Real, - damping: Real, - ) -> Self { - self.0.set_motor(target_pos, target_vel, stiffness, damping); - self +impl RevoluteJointBuilderGlam for RevoluteJointBuilder { + #[cfg(feature = "dim2")] + fn new_glam() -> Self { + Self(RapierRevoluteJoint::new()) } - /// Sets the maximum force the motor can deliver. - #[must_use] - pub fn motor_max_force(mut self, max_force: Real) -> Self { - self.0.set_motor_max_force(max_force); - self + #[cfg(feature = "dim3")] + fn new_glam(axis: Vect) -> Self { + use rapier::math::UnitVector; + let vector = UnitVector::::new_normalize(axis.into()); + Self(RapierRevoluteJoint::new(vector)) } - /// Sets the `[min,max]` limit angles attached bodies can rotate along the joint’s principal axis. #[must_use] - pub fn limits(mut self, limits: [Real; 2]) -> Self { - self.0.set_limits(limits); - self + fn local_anchor1_glam(self, anchor1: Vect) -> Self { + RevoluteJointBuilder::local_anchor1(self, anchor1.into()) } - /// Builds the revolute joint. #[must_use] - pub fn build(self) -> RevoluteJoint { - self.0 - } -} - -impl From for GenericJoint { - fn from(joint: RevoluteJointBuilder) -> GenericJoint { - joint.0.into() + fn local_anchor2_glam(self, anchor2: Vect) -> Self { + RevoluteJointBuilder::local_anchor2(self, anchor2.into()) } }