@@ -13,7 +13,12 @@ use crate::{
1313 prelude:: * ,
1414} ;
1515use bevy:: {
16- ecs:: { entity_disabling:: Disabled , query:: QueryFilter , system:: StaticSystemParam } ,
16+ ecs:: {
17+ change_detection:: Tick ,
18+ entity_disabling:: Disabled ,
19+ query:: QueryFilter ,
20+ system:: { StaticSystemParam , SystemChangeTick } ,
21+ } ,
1722 platform:: collections:: HashSet ,
1823 prelude:: * ,
1924} ;
@@ -36,9 +41,11 @@ impl<C: AnyCollider> Plugin for ColliderTreeUpdatePlugin<C> {
3641 fn build ( & self , app : & mut App ) {
3742 // Initialize resources.
3843 app. init_resource :: < MovedProxies > ( )
39- . init_resource :: < EnlargedProxies > ( ) ;
44+ . init_resource :: < EnlargedProxies > ( )
45+ . init_resource :: < LastDynamicKinematicAabbUpdate > ( ) ;
4046
41- // Add systems for updating collider AABBs.
47+ // Add systems for updating collider AABBs before physics step.
48+ // This accounts for manually moved colliders.
4249 app. add_systems (
4350 PhysicsSchedule ,
4451 (
@@ -53,10 +60,13 @@ impl<C: AnyCollider> Plugin for ColliderTreeUpdatePlugin<C> {
5360 . ambiguous_with_all ( ) ,
5461 ) ;
5562
56- // Clear moved proxies after broad phase .
63+ // Clear moved proxies and update dynamic and kinematic collider AABBs .
5764 app. add_systems (
5865 PhysicsSchedule ,
59- clear_moved_proxies. after ( ColliderTreeSystems :: EndOptimize ) ,
66+ ( clear_moved_proxies, update_dynamic_kinematic_aabbs :: < C > )
67+ . chain ( )
68+ . after ( PhysicsStepSystems :: Finalize )
69+ . before ( PhysicsStepSystems :: Last ) ,
6070 ) ;
6171
6272 // Initialize `ColliderAabb` for colliders.
@@ -433,6 +443,11 @@ fn remove_from_tree_on<E: EntityEvent, B: Bundle, F: QueryFilter>(
433443 * proxy_key = ColliderTreeProxyKey :: PLACEHOLDER ;
434444}
435445
446+ /// A resource for tracking the last system change tick
447+ /// when dynamic or kinematic collider AABBs were updated.
448+ #[ derive( Resource , Default ) ]
449+ struct LastDynamicKinematicAabbUpdate ( Tick ) ;
450+
436451/// A resource for tracking moved proxies.
437452///
438453/// Moved proxies are those whose [`ColliderAabb`] has moved outside of their
@@ -554,16 +569,16 @@ impl EnlargedProxies {
554569}
555570
556571/// Updates the AABBs of colliders attached to dynamic or kinematic rigid bodies.
572+ // TODO: Optimize the change detection.
557573fn update_dynamic_kinematic_aabbs < C : AnyCollider > (
558574 mut colliders : ParamSet < (
559575 Query < (
560- Entity ,
561- & C ,
576+ Ref < C > ,
562577 & mut ColliderAabb ,
563578 & mut EnlargedAabb ,
564579 & ColliderTreeProxyKey ,
565- & Position ,
566- & Rotation ,
580+ Ref < Position > ,
581+ Ref < Rotation > ,
567582 Option < & CollisionMargin > ,
568583 Option < & SpeculativeMargin > ,
569584 ) > ,
@@ -588,9 +603,13 @@ fn update_dynamic_kinematic_aabbs<C: AnyCollider>(
588603 time : Res < Time > ,
589604 collider_context : StaticSystemParam < C :: Context > ,
590605 mut diagnostics : ResMut < BroadPhaseDiagnostics > ,
606+ mut last_tick : ResMut < LastDynamicKinematicAabbUpdate > ,
607+ system_tick : SystemChangeTick ,
591608) {
592609 let start = crate :: utils:: Instant :: now ( ) ;
593610
611+ let this_run = system_tick. this_run ( ) ;
612+
594613 // An upper bound on the number of proxies, for sizing the bit vectors.
595614 // TODO: Use a better way to track the number of proxies.
596615 let max_num_dynamic_proxies = collider_trees. dynamic_tree . proxies . capacity ( ) ;
@@ -615,7 +634,6 @@ fn update_dynamic_kinematic_aabbs<C: AnyCollider>(
615634 |( rb_pos, center_of_mass, lin_vel, ang_vel, body_colliders, has_swept_ccd) | {
616635 for collider_entity in body_colliders. iter ( ) {
617636 let Ok ( (
618- entity,
619637 collider,
620638 mut aabb,
621639 mut enlarged_aabb,
@@ -629,14 +647,22 @@ fn update_dynamic_kinematic_aabbs<C: AnyCollider>(
629647 continue ;
630648 } ;
631649
650+ // Skip if the collider's AABB can't have changed since the last physics tick.
651+ if !pos. last_changed ( ) . is_newer_than ( last_tick. 0 , this_run)
652+ && !rot. last_changed ( ) . is_newer_than ( last_tick. 0 , this_run)
653+ && !collider. last_changed ( ) . is_newer_than ( last_tick. 0 , this_run)
654+ {
655+ continue ;
656+ }
657+
632658 let collision_margin = collision_margin. map_or ( 0.0 , |margin| margin. 0 ) ;
633659 let speculative_margin = if has_swept_ccd {
634660 Scalar :: MAX
635661 } else {
636662 speculative_margin. map_or ( default_speculative_margin, |margin| margin. 0 )
637663 } ;
638664
639- let context = AabbContext :: new ( entity , & * collider_context) ;
665+ let context = AabbContext :: new ( collider_entity , & * collider_context) ;
640666
641667 if speculative_margin <= 0.0 {
642668 * aabb = collider
@@ -774,9 +800,15 @@ fn update_dynamic_kinematic_aabbs<C: AnyCollider>(
774800 tree. bvh . refit_all ( ) ;
775801 }
776802
803+ // Update the last update tick.
804+ last_tick. 0 = this_run;
805+
777806 diagnostics. update += start. elapsed ( ) ;
778807}
779808
809+ // TODO: If we tagged static colliders with their own marker component,
810+ // we could avoid querying for the bodies, and merge this with the
811+ // standalone collider AABB update.
780812/// Updates the AABBs of colliders attached to static rigid bodies.
781813fn update_static_aabbs < C : AnyCollider > (
782814 static_bodies : Query < & RigidBodyColliders , ( Without < SolverBody > , Without < Sleeping > ) > ,
0 commit comments