Skip to content

Commit

Permalink
Merge pull request #101 from Jondolf/insert-position-for-colliders
Browse files Browse the repository at this point in the history
Automatically add `Position` and `Rotation` for colliders
  • Loading branch information
Jondolf authored Jul 30, 2023
2 parents ad7575f + 67909ef commit e189dc7
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 41 deletions.
14 changes: 7 additions & 7 deletions crates/bevy_xpbd_2d/examples/ray_caster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ fn setup(

commands.spawn((
MaterialMesh2dBundle {
mesh: meshes.add(shape::Circle::new(radius as f32).into()).into(),
mesh: meshes.add(shape::Circle::new(radius).into()).into(),
material: materials.add(ColorMaterial::from(Color::rgb(0.2, 0.7, 0.9))),
transform: Transform::from_xyz(
x as f32 * radius * 3.0,
y as f32 * radius * 3.0,
0.0,
),
..default()
},
RigidBody::Kinematic,
Position(Vector::new(
x as Scalar * radius * 3.0,
y as Scalar * radius * 3.0,
)),
Collider::ball(radius),
Collider::ball(radius as Scalar),
));
}
}
Expand Down
12 changes: 9 additions & 3 deletions src/plugins/broad_phase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,16 @@ fn update_aabb(
struct AabbIntervals(Vec<(Entity, ColliderAabb, RigidBody, CollisionLayers)>);

/// Updates [`AabbIntervals`] to keep them in sync with the [`ColliderAabb`]s.
fn update_aabb_intervals(aabbs: Query<&ColliderAabb>, mut intervals: ResMut<AabbIntervals>) {
intervals.0.retain_mut(|(entity, aabb, _, _)| {
if let Ok(new_aabb) = aabbs.get(*entity) {
fn update_aabb_intervals(
aabbs: Query<(&ColliderAabb, Option<&RigidBody>)>,
mut intervals: ResMut<AabbIntervals>,
) {
intervals.0.retain_mut(|(entity, aabb, rb, _)| {
if let Ok((new_aabb, new_rb)) = aabbs.get(*entity) {
*aabb = *new_aabb;
if let Some(new_rb) = new_rb {
*rb = *new_rb;
}
true
} else {
false
Expand Down
99 changes: 82 additions & 17 deletions src/plugins/prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,19 +227,82 @@ fn init_mass_properties(

type ColliderComponents = (
Entity,
// Use transform as default position and rotation if no components for them found
Option<&'static mut Transform>,
Option<&'static GlobalTransform>,
Option<&'static Position>,
Option<&'static Rotation>,
&'static Collider,
Option<&'static ColliderAabb>,
Option<&'static CollidingEntities>,
Option<&'static ColliderMassProperties>,
Option<&'static PreviousColliderMassProperties>,
);

fn init_colliders(mut commands: Commands, colliders: Query<ColliderComponents, Added<Collider>>) {
for (entity, collider, aabb, colliding_entities, mass_properties, previous_mass_properties) in
&colliders
fn init_colliders(
mut commands: Commands,
mut colliders: Query<ColliderComponents, Added<Collider>>,
) {
for (
entity,
mut transform,
global_transform,
pos,
rot,
collider,
aabb,
colliding_entities,
mass_properties,
previous_mass_properties,
) in &mut colliders
{
let mut entity_commands = commands.entity(entity);

if let Some(pos) = pos {
if let Some(ref mut transform) = transform {
#[cfg(feature = "2d")]
{
transform.translation = pos.as_f32().extend(transform.translation.z);
}
#[cfg(feature = "3d")]
{
transform.translation = pos.as_f32();
}
}
} else {
let translation;
#[cfg(feature = "2d")]
{
translation = global_transform.as_ref().map_or(Vector::ZERO, |t| {
Vector::new(t.translation().x as Scalar, t.translation().y as Scalar)
});
}
#[cfg(feature = "3d")]
{
translation = global_transform.as_ref().map_or(Vector::ZERO, |t| {
Vector::new(
t.translation().x as Scalar,
t.translation().y as Scalar,
t.translation().z as Scalar,
)
});
}

entity_commands.insert(Position(translation));
}

if let Some(rot) = rot {
if let Some(mut transform) = transform {
let q: Quaternion = (*rot).into();
transform.rotation = q.as_f32();
}
} else {
let rotation = global_transform.map_or(Rotation::default(), |t| {
t.compute_transform().rotation.into()
});
entity_commands.insert(rotation);
}

if aabb.is_none() {
entity_commands.insert(ColliderAabb::from_shape(collider.get_shape()));
}
Expand All @@ -257,7 +320,7 @@ fn init_colliders(mut commands: Commands, colliders: Query<ColliderComponents, A

type MassPropertiesComponents = (
Entity,
&'static RigidBody,
Option<&'static RigidBody>,
MassPropertiesQuery,
Option<&'static Collider>,
Option<&'static mut ColliderMassProperties>,
Expand Down Expand Up @@ -312,19 +375,21 @@ fn update_mass_properties(mut bodies: Query<MassPropertiesComponents, MassProper
}

// Warn about dynamic bodies with no mass or inertia
let is_mass_valid =
mass_properties.mass.is_finite() && mass_properties.mass.0 >= Scalar::EPSILON;
#[cfg(feature = "2d")]
let is_inertia_valid =
mass_properties.inertia.is_finite() && mass_properties.inertia.0 >= Scalar::EPSILON;
#[cfg(feature = "3d")]
let is_inertia_valid =
mass_properties.inertia.is_finite() && *mass_properties.inertia != Inertia::ZERO;
if rb.is_dynamic() && !(is_mass_valid && is_inertia_valid) {
warn!(
"Dynamic rigid body {:?} has no mass or inertia. This can cause NaN values. Consider adding a `MassPropertiesBundle` or a `Collider` with mass.",
entity
);
if let Some(rb) = rb {
let is_mass_valid =
mass_properties.mass.is_finite() && mass_properties.mass.0 >= Scalar::EPSILON;
#[cfg(feature = "2d")]
let is_inertia_valid =
mass_properties.inertia.is_finite() && mass_properties.inertia.0 >= Scalar::EPSILON;
#[cfg(feature = "3d")]
let is_inertia_valid =
mass_properties.inertia.is_finite() && *mass_properties.inertia != Inertia::ZERO;
if rb.is_dynamic() && !(is_mass_valid && is_inertia_valid) {
warn!(
"Dynamic rigid body {:?} has no mass or inertia. This can cause NaN values. Consider adding a `MassPropertiesBundle` or a `Collider` with mass.",
entity
);
}
}
}
}
30 changes: 16 additions & 14 deletions src/plugins/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,23 +126,25 @@ impl Default for SyncConfig {
#[derive(Component, Deref, DerefMut)]
struct PreviousGlobalTransform(GlobalTransform);

type PhysicsObjectAddedFilter = Or<(Added<RigidBody>, Added<Collider>)>;

fn init_previous_global_transform(
mut commands: Commands,
bodies: Query<(Entity, &GlobalTransform), Added<RigidBody>>,
query: Query<(Entity, &GlobalTransform), PhysicsObjectAddedFilter>,
) {
for (entity, transform) in &bodies {
for (entity, transform) in &query {
commands
.entity(entity)
.insert(PreviousGlobalTransform(*transform));
}
}

/// Copies `GlobalTransform` changes to [`Position`] and [`Rotation`].
/// This allows users to use transforms for moving and positioning bodies.
/// This allows users to use transforms for moving and positioning bodies and colliders.
///
/// To account for hierarchies, transform propagation should be run before this system.
fn transform_to_position(
mut bodies: Query<(
mut query: Query<(
&GlobalTransform,
&PreviousGlobalTransform,
&mut Position,
Expand All @@ -156,7 +158,7 @@ fn transform_to_position(
mut position,
accumulated_translation,
mut rotation,
) in &mut bodies
) in &mut query
{
// Skip entity if the global transform value hasn't changed
if *global_transform == previous_transform.0 {
Expand Down Expand Up @@ -199,16 +201,16 @@ fn transform_to_position(
}
}

type RbSyncQueryComponents = (
type PosToTransformComponents = (
&'static mut Transform,
&'static Position,
&'static Rotation,
Option<&'static Parent>,
);

type RbSyncQueryFilter = Or<(Changed<Position>, Changed<Rotation>)>;
type PosToTransformFilter = Or<(Changed<Position>, Changed<Rotation>)>;

type RigidBodyParentComponents = (
type ParentComponents = (
&'static GlobalTransform,
Option<&'static Position>,
Option<&'static Rotation>,
Expand All @@ -221,10 +223,10 @@ type RigidBodyParentComponents = (
/// based on their own and their parent's [`Position`] and [`Rotation`].
#[cfg(feature = "2d")]
fn position_to_transform(
mut bodies: Query<RbSyncQueryComponents, RbSyncQueryFilter>,
parents: Query<RigidBodyParentComponents, With<Children>>,
mut query: Query<PosToTransformComponents, PosToTransformFilter>,
parents: Query<ParentComponents, With<Children>>,
) {
for (mut transform, pos, rot, parent) in &mut bodies {
for (mut transform, pos, rot, parent) in &mut query {
if let Some(parent) = parent {
if let Ok((parent_transform, parent_pos, parent_rot)) = parents.get(**parent) {
// Compute the global transform of the parent using its Position and Rotation
Expand Down Expand Up @@ -265,10 +267,10 @@ fn position_to_transform(
/// based on their own and their parent's [`Position`] and [`Rotation`].
#[cfg(feature = "3d")]
fn position_to_transform(
mut bodies: Query<RbSyncQueryComponents, RbSyncQueryFilter>,
parents: Query<RigidBodyParentComponents, With<Children>>,
mut query: Query<PosToTransformComponents, PosToTransformFilter>,
parents: Query<ParentComponents, With<Children>>,
) {
for (mut transform, pos, rot, parent) in &mut bodies {
for (mut transform, pos, rot, parent) in &mut query {
if let Some(parent) = parent {
if let Ok((parent_transform, parent_pos, parent_rot)) = parents.get(**parent) {
// Compute the global transform of the parent using its Position and Rotation
Expand Down

0 comments on commit e189dc7

Please sign in to comment.