@@ -2,6 +2,7 @@ use crate::components::{GlobalTransform, Transform};
2
2
use bevy_ecs:: {
3
3
change_detection:: Ref ,
4
4
prelude:: { Changed , DetectChanges , Entity , Query , With , Without } ,
5
+ system:: RemovedComponents ,
5
6
} ;
6
7
use bevy_hierarchy:: { Children , Parent } ;
7
8
@@ -23,23 +24,28 @@ pub fn sync_simple_transforms(
23
24
/// Update [`GlobalTransform`] component of entities based on entity hierarchy and
24
25
/// [`Transform`] component.
25
26
///
27
+ /// Note that this depends on the [`World::clear_trackers`] system to be present.
28
+ ///
26
29
/// Third party plugins should use [`transform_propagate_system_set`](crate::transform_propagate_system_set)
27
30
/// to propagate transforms correctly.
28
31
pub fn propagate_transforms (
29
32
mut root_query : Query <
30
33
( Entity , & Children , Ref < Transform > , & mut GlobalTransform ) ,
31
34
Without < Parent > ,
32
35
> ,
36
+ orphaned : RemovedComponents < Parent > ,
33
37
transform_query : Query < ( Ref < Transform > , & mut GlobalTransform , Option < & Children > ) , With < Parent > > ,
34
38
parent_query : Query < ( Entity , Ref < Parent > ) > ,
35
39
) {
40
+ let mut orphaned = orphaned. iter ( ) . collect :: < Vec < _ > > ( ) ;
41
+ orphaned. sort_unstable ( ) ;
36
42
root_query. par_for_each_mut (
37
43
// The differing depths and sizes of hierarchy trees causes the work for each root to be
38
44
// different. A batch size of 1 ensures that each tree gets it's own task and multiple
39
45
// large trees are not clumped together.
40
46
1 ,
41
47
|( entity, children, transform, mut global_transform) | {
42
- let changed = transform. is_changed ( ) ;
48
+ let changed = transform. is_changed ( ) || orphaned . binary_search ( & entity ) . is_ok ( ) ;
43
49
if changed {
44
50
* global_transform = GlobalTransform :: from ( * transform) ;
45
51
}
@@ -165,21 +171,62 @@ mod test {
165
171
use bevy_tasks:: { ComputeTaskPool , TaskPool } ;
166
172
167
173
use crate :: components:: { GlobalTransform , Transform } ;
168
- use crate :: systems:: * ;
169
- use crate :: TransformBundle ;
174
+ use crate :: { transform_propagate_system_set, TransformBundle } ;
170
175
use bevy_hierarchy:: { BuildChildren , BuildWorldChildren , Children , Parent } ;
171
176
172
177
#[ derive( StageLabel ) ]
173
178
struct Update ;
174
179
180
+ #[ test]
181
+ fn correct_parent_removed ( ) {
182
+ ComputeTaskPool :: init ( TaskPool :: default) ;
183
+ let mut world = World :: default ( ) ;
184
+
185
+ let mut update_stage = SystemStage :: parallel ( ) ;
186
+ update_stage. add_system_set ( transform_propagate_system_set ( ) ) ;
187
+
188
+ let mut schedule = Schedule :: default ( ) ;
189
+ schedule. add_stage ( Update , update_stage) ;
190
+
191
+ let mut command_queue = CommandQueue :: default ( ) ;
192
+ let mut commands = Commands :: new ( & mut command_queue, & world) ;
193
+ let root = commands
194
+ . spawn ( TransformBundle :: from_transform ( Transform :: from_xyz (
195
+ 9.9 , 9.9 , 9.9 ,
196
+ ) ) )
197
+ . id ( ) ;
198
+ let parent = commands. spawn ( TransformBundle :: IDENTITY ) . id ( ) ;
199
+ let child = commands. spawn ( TransformBundle :: IDENTITY ) . id ( ) ;
200
+ commands. entity ( parent) . set_parent ( root) ;
201
+ commands. entity ( child) . set_parent ( parent) ;
202
+ command_queue. apply ( & mut world) ;
203
+ schedule. run ( & mut world) ;
204
+
205
+ assert_ne ! (
206
+ world. get:: <GlobalTransform >( parent) . unwrap( ) ,
207
+ & GlobalTransform :: from( Transform :: IDENTITY )
208
+ ) ;
209
+
210
+ // Remove parent of `parent`
211
+ let mut command_queue = CommandQueue :: default ( ) ;
212
+ let mut commands = Commands :: new ( & mut command_queue, & world) ;
213
+ commands. entity ( parent) . remove_parent ( ) ;
214
+ command_queue. apply ( & mut world) ;
215
+ schedule. run ( & mut world) ;
216
+
217
+ assert_eq ! (
218
+ world. get:: <GlobalTransform >( parent) . unwrap( ) ,
219
+ & GlobalTransform :: from( Transform :: IDENTITY )
220
+ ) ;
221
+ }
222
+
175
223
#[ test]
176
224
fn did_propagate ( ) {
177
225
ComputeTaskPool :: init ( TaskPool :: default) ;
178
226
let mut world = World :: default ( ) ;
179
227
180
228
let mut update_stage = SystemStage :: parallel ( ) ;
181
- update_stage. add_system ( sync_simple_transforms) ;
182
- update_stage. add_system ( propagate_transforms) ;
229
+ update_stage. add_system_set ( transform_propagate_system_set ( ) ) ;
183
230
184
231
let mut schedule = Schedule :: default ( ) ;
185
232
schedule. add_stage ( Update , update_stage) ;
@@ -220,8 +267,7 @@ mod test {
220
267
let mut world = World :: default ( ) ;
221
268
222
269
let mut update_stage = SystemStage :: parallel ( ) ;
223
- update_stage. add_system ( sync_simple_transforms) ;
224
- update_stage. add_system ( propagate_transforms) ;
270
+ update_stage. add_system_set ( transform_propagate_system_set ( ) ) ;
225
271
226
272
let mut schedule = Schedule :: default ( ) ;
227
273
schedule. add_stage ( Update , update_stage) ;
@@ -264,8 +310,7 @@ mod test {
264
310
let mut world = World :: default ( ) ;
265
311
266
312
let mut update_stage = SystemStage :: parallel ( ) ;
267
- update_stage. add_system ( sync_simple_transforms) ;
268
- update_stage. add_system ( propagate_transforms) ;
313
+ update_stage. add_system_set ( transform_propagate_system_set ( ) ) ;
269
314
270
315
let mut schedule = Schedule :: default ( ) ;
271
316
schedule. add_stage ( Update , update_stage) ;
@@ -344,8 +389,7 @@ mod test {
344
389
let mut app = App :: new ( ) ;
345
390
ComputeTaskPool :: init ( TaskPool :: default) ;
346
391
347
- app. add_system ( sync_simple_transforms) ;
348
- app. add_system ( propagate_transforms) ;
392
+ app. add_system_set ( transform_propagate_system_set ( ) ) ;
349
393
350
394
let translation = vec3 ( 1.0 , 0.0 , 0.0 ) ;
351
395
@@ -391,8 +435,7 @@ mod test {
391
435
let mut temp = World :: new ( ) ;
392
436
let mut app = App :: new ( ) ;
393
437
394
- app. add_system ( propagate_transforms)
395
- . add_system ( sync_simple_transforms) ;
438
+ app. add_system_set ( transform_propagate_system_set ( ) ) ;
396
439
397
440
fn setup_world ( world : & mut World ) -> ( Entity , Entity ) {
398
441
let mut grandchild = Entity :: from_raw ( 0 ) ;
0 commit comments