@@ -2,6 +2,7 @@ use crate::components::{GlobalTransform, Transform};
22use bevy_ecs:: {
33 change_detection:: Ref ,
44 prelude:: { Changed , DetectChanges , Entity , Query , With , Without } ,
5+ system:: { ParamSet , RemovedComponents } ,
56} ;
67use bevy_hierarchy:: { Children , Parent } ;
78
@@ -10,16 +11,29 @@ use bevy_hierarchy::{Children, Parent};
1011/// Third party plugins should use [`transform_propagate_system_set`](crate::transform_propagate_system_set)
1112/// to propagate transforms correctly.
1213pub fn sync_simple_transforms (
13- mut query : Query <
14- ( & Transform , & mut GlobalTransform ) ,
15- ( Changed < Transform > , Without < Parent > , Without < Children > ) ,
16- > ,
14+ mut query : ParamSet < (
15+ Query <
16+ ( & Transform , & mut GlobalTransform ) ,
17+ ( Changed < Transform > , Without < Parent > , Without < Children > ) ,
18+ > ,
19+ Query < ( Ref < Transform > , & mut GlobalTransform ) , Without < Children > > ,
20+ ) > ,
21+ orphaned : RemovedComponents < Parent > ,
1722) {
1823 query
24+ . p0 ( )
1925 . par_iter_mut ( )
2026 . for_each_mut ( |( transform, mut global_transform) | {
2127 * global_transform = GlobalTransform :: from ( * transform) ;
2228 } ) ;
29+ // updated orphaned entities
30+ let mut query = query. p1 ( ) ;
31+ let mut iter = query. iter_many_mut ( orphaned. iter ( ) ) ;
32+ while let Some ( ( transform, mut global_transform) ) = iter. fetch_next ( ) {
33+ if !transform. is_changed ( ) {
34+ * global_transform = GlobalTransform :: from ( * transform) ;
35+ }
36+ }
2337}
2438
2539/// Update [`GlobalTransform`] component of entities based on entity hierarchy and
@@ -32,12 +46,15 @@ pub fn propagate_transforms(
3246 ( Entity , & Children , Ref < Transform > , & mut GlobalTransform ) ,
3347 Without < Parent > ,
3448 > ,
49+ orphaned : RemovedComponents < Parent > ,
3550 transform_query : Query < ( Ref < Transform > , & mut GlobalTransform , Option < & Children > ) , With < Parent > > ,
3651 parent_query : Query < ( Entity , Ref < Parent > ) > ,
3752) {
53+ let mut orphaned = orphaned. iter ( ) . collect :: < Vec < _ > > ( ) ;
54+ orphaned. sort_unstable ( ) ;
3855 root_query. par_iter_mut ( ) . for_each_mut (
3956 |( entity, children, transform, mut global_transform) | {
40- let changed = transform. is_changed ( ) ;
57+ let changed = transform. is_changed ( ) || orphaned . binary_search ( & entity ) . is_ok ( ) ;
4158 if changed {
4259 * global_transform = GlobalTransform :: from ( * transform) ;
4360 }
@@ -163,21 +180,74 @@ mod test {
163180 use bevy_tasks:: { ComputeTaskPool , TaskPool } ;
164181
165182 use crate :: components:: { GlobalTransform , Transform } ;
166- use crate :: systems:: * ;
167- use crate :: TransformBundle ;
183+ use crate :: { transform_propagate_system_set, TransformBundle } ;
168184 use bevy_hierarchy:: { BuildChildren , BuildWorldChildren , Children , Parent } ;
169185
170186 #[ derive( StageLabel ) ]
171187 struct Update ;
172188
189+ #[ test]
190+ fn correct_parent_removed ( ) {
191+ ComputeTaskPool :: init ( TaskPool :: default) ;
192+ let mut world = World :: default ( ) ;
193+ let offset_global_transform =
194+ |offset| GlobalTransform :: from ( Transform :: from_xyz ( offset, offset, offset) ) ;
195+ let offset_transform =
196+ |offset| TransformBundle :: from_transform ( Transform :: from_xyz ( offset, offset, offset) ) ;
197+
198+ let mut update_stage = SystemStage :: parallel ( ) ;
199+ update_stage. add_system_set ( transform_propagate_system_set ( ) ) ;
200+
201+ let mut schedule = Schedule :: default ( ) ;
202+ schedule. add_stage ( Update , update_stage) ;
203+
204+ let mut command_queue = CommandQueue :: default ( ) ;
205+ let mut commands = Commands :: new ( & mut command_queue, & world) ;
206+ let root = commands. spawn ( offset_transform ( 3.3 ) ) . id ( ) ;
207+ let parent = commands. spawn ( offset_transform ( 4.4 ) ) . id ( ) ;
208+ let child = commands. spawn ( offset_transform ( 5.5 ) ) . id ( ) ;
209+ commands. entity ( parent) . set_parent ( root) ;
210+ commands. entity ( child) . set_parent ( parent) ;
211+ command_queue. apply ( & mut world) ;
212+ schedule. run ( & mut world) ;
213+
214+ assert_ne ! (
215+ world. get:: <GlobalTransform >( parent) . unwrap( ) ,
216+ & GlobalTransform :: from( Transform :: IDENTITY )
217+ ) ;
218+
219+ // Remove parent of `parent`
220+ let mut command_queue = CommandQueue :: default ( ) ;
221+ let mut commands = Commands :: new ( & mut command_queue, & world) ;
222+ commands. entity ( parent) . remove_parent ( ) ;
223+ command_queue. apply ( & mut world) ;
224+ schedule. run ( & mut world) ;
225+
226+ assert_eq ! (
227+ world. get:: <GlobalTransform >( parent) . unwrap( ) ,
228+ & offset_global_transform( 4.4 )
229+ ) ;
230+
231+ // Remove parent of `child`
232+ let mut command_queue = CommandQueue :: default ( ) ;
233+ let mut commands = Commands :: new ( & mut command_queue, & world) ;
234+ commands. entity ( child) . remove_parent ( ) ;
235+ command_queue. apply ( & mut world) ;
236+ schedule. run ( & mut world) ;
237+
238+ assert_eq ! (
239+ world. get:: <GlobalTransform >( child) . unwrap( ) ,
240+ & offset_global_transform( 5.5 )
241+ ) ;
242+ }
243+
173244 #[ test]
174245 fn did_propagate ( ) {
175246 ComputeTaskPool :: init ( TaskPool :: default) ;
176247 let mut world = World :: default ( ) ;
177248
178249 let mut update_stage = SystemStage :: parallel ( ) ;
179- update_stage. add_system ( sync_simple_transforms) ;
180- update_stage. add_system ( propagate_transforms) ;
250+ update_stage. add_system_set ( transform_propagate_system_set ( ) ) ;
181251
182252 let mut schedule = Schedule :: default ( ) ;
183253 schedule. add_stage ( Update , update_stage) ;
@@ -218,8 +288,7 @@ mod test {
218288 let mut world = World :: default ( ) ;
219289
220290 let mut update_stage = SystemStage :: parallel ( ) ;
221- update_stage. add_system ( sync_simple_transforms) ;
222- update_stage. add_system ( propagate_transforms) ;
291+ update_stage. add_system_set ( transform_propagate_system_set ( ) ) ;
223292
224293 let mut schedule = Schedule :: default ( ) ;
225294 schedule. add_stage ( Update , update_stage) ;
@@ -262,8 +331,7 @@ mod test {
262331 let mut world = World :: default ( ) ;
263332
264333 let mut update_stage = SystemStage :: parallel ( ) ;
265- update_stage. add_system ( sync_simple_transforms) ;
266- update_stage. add_system ( propagate_transforms) ;
334+ update_stage. add_system_set ( transform_propagate_system_set ( ) ) ;
267335
268336 let mut schedule = Schedule :: default ( ) ;
269337 schedule. add_stage ( Update , update_stage) ;
@@ -342,8 +410,7 @@ mod test {
342410 let mut app = App :: new ( ) ;
343411 ComputeTaskPool :: init ( TaskPool :: default) ;
344412
345- app. add_system ( sync_simple_transforms) ;
346- app. add_system ( propagate_transforms) ;
413+ app. add_system_set ( transform_propagate_system_set ( ) ) ;
347414
348415 let translation = vec3 ( 1.0 , 0.0 , 0.0 ) ;
349416
@@ -389,8 +456,7 @@ mod test {
389456 let mut temp = World :: new ( ) ;
390457 let mut app = App :: new ( ) ;
391458
392- app. add_system ( propagate_transforms)
393- . add_system ( sync_simple_transforms) ;
459+ app. add_system_set ( transform_propagate_system_set ( ) ) ;
394460
395461 fn setup_world ( world : & mut World ) -> ( Entity , Entity ) {
396462 let mut grandchild = Entity :: from_raw ( 0 ) ;
0 commit comments