Skip to content

Commit b52f00a

Browse files
committed
Add, update, remove collider parent based on hierarchy changes
1 parent c99ccc7 commit b52f00a

File tree

1 file changed

+102
-2
lines changed

1 file changed

+102
-2
lines changed

src/plugin/systems.rs

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ use crate::pipeline::{CollisionEvent, ContactForceEvent};
1515
use crate::plugin::configuration::{SimulationToRenderTime, TimestepMode};
1616
use crate::plugin::{RapierConfiguration, RapierContext};
1717
use crate::prelude::{
18-
BevyPhysicsHooks, BevyPhysicsHooksAdapter, CollidingEntities, KinematicCharacterController,
19-
KinematicCharacterControllerOutput, RigidBodyDisabled, ColliderParent,
18+
BevyPhysicsHooks, BevyPhysicsHooksAdapter, ColliderParent, CollidingEntities,
19+
KinematicCharacterController, KinematicCharacterControllerOutput, RigidBodyDisabled,
2020
};
2121
use crate::utils;
2222
use bevy::ecs::system::{StaticSystemParam, SystemParamItem};
23+
use bevy::hierarchy::HierarchyEvent;
2324
use bevy::prelude::*;
2425
use rapier::prelude::*;
2526
use std::collections::HashMap;
@@ -117,6 +118,81 @@ pub fn apply_scale(
117118
}
118119
}
119120

121+
/// System responsible for detecting changes in the hierarchy that would
122+
/// affect the collider's parent rigid body.
123+
pub fn collect_collider_hierarchy_changes(
124+
mut commands: Commands,
125+
126+
mut hierarchy_events: EventReader<HierarchyEvent>,
127+
parents: Query<&Parent>,
128+
childrens: Query<&Children>,
129+
rigid_bodies: Query<&RigidBody>,
130+
colliders: Query<&Collider>,
131+
mut collider_parents: Query<&mut ColliderParent>,
132+
) {
133+
let child_colliders = |entity: Entity| -> Vec<Entity> {
134+
let mut found = Vec::new();
135+
let mut possibilities = vec![entity];
136+
while let Some(entity) = possibilities.pop() {
137+
if rigid_bodies.contains(entity) {
138+
continue;
139+
}
140+
141+
if colliders.contains(entity) {
142+
found.push(entity);
143+
}
144+
145+
if let Ok(children) = childrens.get(entity) {
146+
possibilities.extend(children.iter());
147+
} else {
148+
continue;
149+
};
150+
}
151+
152+
found
153+
};
154+
155+
let parent_rigid_body = |mut entity: Entity| -> Option<Entity> {
156+
loop {
157+
if rigid_bodies.contains(entity) {
158+
return Some(entity);
159+
}
160+
161+
if let Ok(parent) = parents.get(entity) {
162+
entity = parent.get();
163+
} else {
164+
return None;
165+
}
166+
}
167+
};
168+
169+
for event in hierarchy_events.iter() {
170+
match event {
171+
HierarchyEvent::ChildAdded { child, .. } | HierarchyEvent::ChildMoved { child, .. } => {
172+
let colliders = child_colliders(*child);
173+
let Some(rigid_body) = parent_rigid_body(*child) else { continue };
174+
175+
for collider in colliders {
176+
let new_collider_parent = ColliderParent(rigid_body);
177+
if let Ok(mut collider_parent) = collider_parents.get_mut(collider) {
178+
*collider_parent = new_collider_parent;
179+
} else {
180+
commands.entity(collider).insert(new_collider_parent);
181+
}
182+
}
183+
}
184+
HierarchyEvent::ChildRemoved { child, .. } => {
185+
let colliders = child_colliders(*child);
186+
for collider in colliders {
187+
if collider_parents.contains(collider) {
188+
commands.entity(collider).remove::<ColliderParent>();
189+
}
190+
}
191+
}
192+
}
193+
}
194+
}
195+
120196
/// System responsible for applying changes the user made to a collider-related component.
121197
pub fn apply_collider_user_changes(
122198
config: Res<RapierConfiguration>,
@@ -125,6 +201,7 @@ pub fn apply_collider_user_changes(
125201
(&RapierColliderHandle, &GlobalTransform),
126202
(Without<RapierRigidBodyHandle>, Changed<GlobalTransform>),
127203
>,
204+
changed_collider_parents: Query<(&RapierColliderHandle, &ColliderParent), Changed<ColliderParent>>,
128205
changed_shapes: Query<(&RapierColliderHandle, &Collider), Changed<Collider>>,
129206
changed_active_events: Query<(&RapierColliderHandle, &ActiveEvents), Changed<ActiveEvents>>,
130207
changed_active_hooks: Query<(&RapierColliderHandle, &ActiveHooks), Changed<ActiveHooks>>,
@@ -163,6 +240,17 @@ pub fn apply_collider_user_changes(
163240
}
164241
}
165242

243+
for (handle, collider_parent) in changed_collider_parents.iter() {
244+
if let Some(body_handle) = context.entity2body.get(&collider_parent.0).copied() {
245+
let RapierContext {
246+
ref mut colliders,
247+
ref mut bodies,
248+
..
249+
} = *context;
250+
colliders.set_parent(handle.0, Some(body_handle), bodies);
251+
}
252+
}
253+
166254
for (handle, shape) in changed_shapes.iter() {
167255
if let Some(co) = context.colliders.get_mut(handle.0) {
168256
let mut scaled_shape = shape.clone();
@@ -1092,6 +1180,7 @@ pub fn sync_removals(
10921180
mut removed_sensors: RemovedComponents<Sensor>,
10931181
mut removed_rigid_body_disabled: RemovedComponents<RigidBodyDisabled>,
10941182
mut removed_colliders_disabled: RemovedComponents<ColliderDisabled>,
1183+
mut removed_collider_parents: RemovedComponents<ColliderParent>,
10951184
) {
10961185
/*
10971186
* Rigid-bodies removal detection.
@@ -1210,6 +1299,17 @@ pub fn sync_removals(
12101299
}
12111300
}
12121301

1302+
for entity in removed_collider_parents.iter() {
1303+
if let Some(handle) = context.entity2collider.get(&entity) {
1304+
let RapierContext {
1305+
ref mut colliders,
1306+
ref mut bodies,
1307+
..
1308+
} = *context;
1309+
colliders.set_parent(*handle, None, bodies);
1310+
}
1311+
}
1312+
12131313
// TODO: update mass props after collider removal.
12141314
// TODO: what about removing forces?
12151315
}

0 commit comments

Comments
 (0)