@@ -15,11 +15,12 @@ use crate::pipeline::{CollisionEvent, ContactForceEvent};
1515use crate :: plugin:: configuration:: { SimulationToRenderTime , TimestepMode } ;
1616use crate :: plugin:: { RapierConfiguration , RapierContext } ;
1717use crate :: prelude:: {
18- BevyPhysicsHooks , BevyPhysicsHooksAdapter , CollidingEntities , KinematicCharacterController ,
19- KinematicCharacterControllerOutput , RigidBodyDisabled , ColliderParent ,
18+ BevyPhysicsHooks , BevyPhysicsHooksAdapter , ColliderParent , CollidingEntities ,
19+ KinematicCharacterController , KinematicCharacterControllerOutput , RigidBodyDisabled ,
2020} ;
2121use crate :: utils;
2222use bevy:: ecs:: system:: { StaticSystemParam , SystemParamItem } ;
23+ use bevy:: hierarchy:: HierarchyEvent ;
2324use bevy:: prelude:: * ;
2425use rapier:: prelude:: * ;
2526use 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.
121197pub 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