Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/collision/collider/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ impl<C: ScalableCollider> Plugin for ColliderBackendPlugin<C> {
world
.commands()
.entity(ctx.entity)
.remove::<ColliderMarker>();
.try_remove::<ColliderMarker>();

let entity_ref = world.entity_mut(ctx.entity);

Expand Down
53 changes: 52 additions & 1 deletion src/collision/collider/collider_hierarchy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::prelude::*;
use bevy::{
ecs::{
component::HookContext,
relationship::{Relationship, RelationshipHookMode},
relationship::{Relationship, RelationshipHookMode, RelationshipSourceCollection},
world::DeferredWorld,
},
prelude::*,
Expand Down Expand Up @@ -127,6 +127,57 @@ impl Relationship for ColliderOf {
);
}
}

fn on_replace(
mut world: DeferredWorld,
HookContext {
entity,
relationship_hook_mode,
..
}: HookContext,
) {
// This is largely the same as the default implementation,
// but does not panic if the relationship target does not exist.

match relationship_hook_mode {
RelationshipHookMode::Run => {}
RelationshipHookMode::Skip => return,
RelationshipHookMode::RunIfNotLinked => {
if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
return;
}
}
}
let rigid_body = world.entity(entity).get::<Self>().unwrap().get();
if let Ok(mut rigid_body_mut) = world.get_entity_mut(rigid_body) {
if let Some(mut relationship_target) =
rigid_body_mut.get_mut::<Self::RelationshipTarget>()
{
RelationshipSourceCollection::remove(
relationship_target.collection_mut_risky(),
entity,
);
if relationship_target.len() == 0 {
if let Ok(mut entity) = world.commands().get_entity(rigid_body) {
// this "remove" operation must check emptiness because in the event that an identical
// relationship is inserted on top, this despawn would result in the removal of that identical
// relationship ... not what we want!
entity.queue_handled(
|mut entity: EntityWorldMut| {
if entity
.get::<Self::RelationshipTarget>()
.is_some_and(RelationshipTarget::is_empty)
{
entity.remove::<Self::RelationshipTarget>();
}
},
|_, _| {},
);
}
}
}
}
}
}

/// A [`RelationshipTarget`] component that tracks which colliders are attached to a [`RigidBody`].
Expand Down
4 changes: 2 additions & 2 deletions src/collision/collider/collider_hierarchy/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl Plugin for ColliderHierarchyPlugin {

// Make sure the collider is on the same entity as the rigid body.
if query.contains(entity) {
commands.entity(entity).remove::<ColliderOf>();
commands.entity(entity).try_remove::<ColliderOf>();
}
},
);
Expand Down Expand Up @@ -117,7 +117,7 @@ fn on_rigid_body_removed(
for collider_entity in colliders.iter() {
commands
.entity(collider_entity)
.remove::<(ColliderOf, ColliderTransform)>();
.try_remove::<(ColliderOf, ColliderTransform)>();
}
}
}