transform|ui: fix transform update lag
This commit is contained in:
		
							parent
							
								
									d79339ea62
								
							
						
					
					
						commit
						6cad80d572
					
				| @ -164,6 +164,15 @@ impl AppBuilder { | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_system_to_stage_front( | ||||
|         &mut self, | ||||
|         stage_name: &'static str, | ||||
|         system: Box<dyn System>, | ||||
|     ) -> &mut Self { | ||||
|         self.app.schedule.add_system_to_stage_front(stage_name, system); | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_systems_to_stage( | ||||
|         &mut self, | ||||
|         stage_name: &'static str, | ||||
|  | ||||
| @ -98,6 +98,30 @@ impl Schedule { | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_system_to_stage_front( | ||||
|         &mut self, | ||||
|         stage_name: impl Into<Cow<'static, str>>, | ||||
|         system: Box<dyn System>, | ||||
|     ) -> &mut Self { | ||||
|         let stage_name = stage_name.into(); | ||||
|         let systems = self | ||||
|             .stages | ||||
|             .get_mut(&stage_name) | ||||
|             .unwrap_or_else(|| panic!("Stage does not exist: {}", stage_name)); | ||||
|         if self.system_ids.contains(&system.id()) { | ||||
|             panic!( | ||||
|                 "System with id {:?} ({}) already exists", | ||||
|                 system.id(), | ||||
|                 system.name() | ||||
|             ); | ||||
|         } | ||||
|         self.system_ids.insert(system.id()); | ||||
|         systems.insert(0, Arc::new(Mutex::new(system))); | ||||
| 
 | ||||
|         self.generation += 1; | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     pub fn run(&mut self, world: &mut World, resources: &mut Resources) { | ||||
|         for stage_name in self.stage_order.iter() { | ||||
|             if let Some(stage_systems) = self.stages.get_mut(stage_name) { | ||||
|  | ||||
| @ -307,13 +307,13 @@ impl Commands { | ||||
|         commands.current_entity | ||||
|     } | ||||
| 
 | ||||
|     pub fn for_current_entity(&mut self, mut func: impl FnMut(Entity)) -> &mut Self { | ||||
|     pub fn for_current_entity(&mut self, mut f: impl FnMut(Entity)) -> &mut Self { | ||||
|         { | ||||
|             let commands = self.commands.lock().unwrap(); | ||||
|             let current_entity = commands | ||||
|                 .current_entity | ||||
|                 .expect("The 'current entity' is not set. You should spawn an entity first."); | ||||
|             func(current_entity); | ||||
|             f(current_entity); | ||||
|         } | ||||
|         self | ||||
|     } | ||||
|  | ||||
| @ -16,7 +16,7 @@ impl WorldWriter for InsertChildren { | ||||
|                     *child, | ||||
|                     ( | ||||
|                         Parent(self.parent), | ||||
|                         PreviousParent(None), | ||||
|                         PreviousParent(Some(self.parent)), | ||||
|                         LocalTransform::default(), | ||||
|                     ), | ||||
|                 ) | ||||
| @ -57,7 +57,7 @@ impl WorldWriter for PushChildren { | ||||
|                     *child, | ||||
|                     ( | ||||
|                         Parent(self.parent), | ||||
|                         PreviousParent(None), | ||||
|                         PreviousParent(Some(self.parent)), | ||||
|                         LocalTransform::default(), | ||||
|                     ), | ||||
|                 ) | ||||
| @ -119,7 +119,7 @@ impl<'a> ChildBuilder<'a> { | ||||
| } | ||||
| 
 | ||||
| pub trait BuildChildren { | ||||
|     fn with_children(&mut self, parent: impl FnMut(&mut ChildBuilder)) -> &mut Self; | ||||
|     fn with_children(&mut self, f: impl FnMut(&mut ChildBuilder)) -> &mut Self; | ||||
|     fn push_children(&mut self, parent: Entity, children: &[Entity]) -> &mut Self; | ||||
|     fn insert_children(&mut self, parent: Entity, index: usize, children: &[Entity]) -> &mut Self; | ||||
| } | ||||
| @ -252,11 +252,11 @@ mod tests { | ||||
| 
 | ||||
|         assert_eq!( | ||||
|             *world.get::<PreviousParent>(child1).unwrap(), | ||||
|             PreviousParent(None) | ||||
|             PreviousParent(Some(parent)) | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             *world.get::<PreviousParent>(child2).unwrap(), | ||||
|             PreviousParent(None) | ||||
|             PreviousParent(Some(parent)) | ||||
|         ); | ||||
| 
 | ||||
|         assert!(world.get::<LocalTransform>(child1).is_ok()); | ||||
| @ -291,11 +291,11 @@ mod tests { | ||||
| 
 | ||||
|         assert_eq!( | ||||
|             *world.get::<PreviousParent>(child1).unwrap(), | ||||
|             PreviousParent(None) | ||||
|             PreviousParent(Some(parent)) | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             *world.get::<PreviousParent>(child2).unwrap(), | ||||
|             PreviousParent(None) | ||||
|             PreviousParent(Some(parent)) | ||||
|         ); | ||||
| 
 | ||||
|         assert!(world.get::<LocalTransform>(child1).is_ok()); | ||||
| @ -313,11 +313,11 @@ mod tests { | ||||
|         assert_eq!(*world.get::<Parent>(child4).unwrap(), Parent(parent)); | ||||
|         assert_eq!( | ||||
|             *world.get::<PreviousParent>(child3).unwrap(), | ||||
|             PreviousParent(None) | ||||
|             PreviousParent(Some(parent)) | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             *world.get::<PreviousParent>(child4).unwrap(), | ||||
|             PreviousParent(None) | ||||
|             PreviousParent(Some(parent)) | ||||
|         ); | ||||
| 
 | ||||
|         assert!(world.get::<LocalTransform>(child3).is_ok()); | ||||
|  | ||||
| @ -36,7 +36,7 @@ pub fn parent_update_system( | ||||
|     } | ||||
| 
 | ||||
|     // Tracks all newly created `Children` Components this frame.
 | ||||
|     let mut children_additions = HashMap::<Entity, SmallVec<[Entity; 8]>>::with_capacity(16); | ||||
|     let mut children_additions = HashMap::<Entity, SmallVec<[Entity; 8]>>::new(); | ||||
| 
 | ||||
|     // Entities with a changed Parent (that also have a PreviousParent, even if None)
 | ||||
|     for (entity, parent, mut previous_parent) in &mut changed_parent_query.iter() { | ||||
| @ -108,7 +108,7 @@ pub fn hierarchy_maintenance_systems() -> Vec<Box<dyn System>> { | ||||
| #[cfg(test)] | ||||
| mod test { | ||||
|     use super::*; | ||||
|     use crate::transform_systems; | ||||
|     use crate::{hierarchy::BuildChildren, transform_systems}; | ||||
|     use bevy_ecs::{Resources, Schedule, World}; | ||||
| 
 | ||||
|     #[test] | ||||
| @ -123,26 +123,21 @@ mod test { | ||||
|         } | ||||
| 
 | ||||
|         // Add parent entities
 | ||||
|         let parent = world.spawn((Translation::new(1.0, 0.0, 0.0), Transform::identity())); | ||||
|         let children = world | ||||
|             .spawn_batch(vec![ | ||||
|                 ( | ||||
|                     Translation::new(0.0, 2.0, 0.0), | ||||
|                     LocalTransform::identity(), | ||||
|                     Transform::identity(), | ||||
|                     Parent(parent), | ||||
|                 ), | ||||
|                 ( | ||||
|                     Translation::new(0.0, 0.0, 3.0), | ||||
|                     LocalTransform::identity(), | ||||
|                     Transform::identity(), | ||||
|                     Parent(parent), | ||||
|                 ), | ||||
|             ]) | ||||
|             .collect::<Vec<Entity>>(); | ||||
| 
 | ||||
|         schedule.run(&mut world, &mut resources); | ||||
|         // TODO: this should be in sync after one run
 | ||||
|         let mut commands = Commands::default(); | ||||
|         let mut parent = None; | ||||
|         let mut children = Vec::new(); | ||||
|         commands | ||||
|             .spawn((Translation::new(1.0, 0.0, 0.0), Transform::identity())) | ||||
|             .for_current_entity(|entity| parent = Some(entity)) | ||||
|             .with_children(|parent| { | ||||
|                 parent | ||||
|                     .spawn((Translation::new(0.0, 2.0, 0.0), Transform::identity())) | ||||
|                     .for_current_entity(|entity| children.push(entity)) | ||||
|                     .spawn((Translation::new(0.0, 0.0, 3.0), Transform::identity())) | ||||
|                     .for_current_entity(|entity| children.push(entity)); | ||||
|             }); | ||||
|         let parent = parent.unwrap(); | ||||
|         commands.apply(&mut world, &mut resources); | ||||
|         schedule.run(&mut world, &mut resources); | ||||
| 
 | ||||
|         assert_eq!( | ||||
|  | ||||
| @ -25,7 +25,7 @@ impl<'a, 'b> WorldChildBuilder<'a, 'b> { | ||||
|             .spawn_as_entity(entity, components) | ||||
|             .with_bundle(( | ||||
|                 Parent(parent_entity), | ||||
|                 PreviousParent(None), | ||||
|                 PreviousParent(Some(parent_entity)), | ||||
|                 LocalTransform::default(), | ||||
|             )); | ||||
|         { | ||||
|  | ||||
| @ -39,6 +39,6 @@ impl AppPlugin for TransformPlugin { | ||||
|             .register_component::<NonUniformScale>() | ||||
|             // add transform systems to startup so the first update is "correct"
 | ||||
|             .add_startup_systems(transform_systems()) | ||||
|             .add_systems(transform_systems()); | ||||
|             .add_systems_to_stage(stage::POST_UPDATE, transform_systems()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -62,7 +62,7 @@ fn propagate_recursive( | ||||
| #[cfg(test)] | ||||
| mod test { | ||||
|     use super::*; | ||||
|     use crate::transform_systems; | ||||
|     use crate::{hierarchy::BuildChildren, transform_systems}; | ||||
|     use bevy_ecs::{Resources, Schedule, World}; | ||||
|     use bevy_math::{Mat4, Vec3}; | ||||
| 
 | ||||
| @ -95,9 +95,9 @@ mod test { | ||||
|                 ), | ||||
|             ]) | ||||
|             .collect::<Vec<Entity>>(); | ||||
| 
 | ||||
|         // TODO: ideally we dont need three runs to keep transforms in sync.
 | ||||
|         // command buffers should be flushed in the appropriate places
 | ||||
|         // we need to run the schedule three times because components need to be filled in
 | ||||
|         // to resolve this problem in code, just add the correct components, or use Commands
 | ||||
|         // which adds all of the components needed with the correct state (see next test)
 | ||||
|         schedule.run(&mut world, &mut resources); | ||||
|         schedule.run(&mut world, &mut resources); | ||||
|         schedule.run(&mut world, &mut resources); | ||||
| @ -114,4 +114,43 @@ mod test { | ||||
|                 * Mat4::from_translation(Vec3::new(0.0, 0.0, 3.0)) | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn did_propagate_command_buffer() { | ||||
|         let mut world = World::default(); | ||||
|         let mut resources = Resources::default(); | ||||
| 
 | ||||
|         let mut schedule = Schedule::default(); | ||||
|         schedule.add_stage("update"); | ||||
|         for system in transform_systems() { | ||||
|             schedule.add_system_to_stage("update", system); | ||||
|         } | ||||
| 
 | ||||
|         // Root entity
 | ||||
|         let mut commands = Commands::default(); | ||||
|         let mut children = Vec::new(); | ||||
|         commands | ||||
|             .spawn((Translation::new(1.0, 0.0, 0.0), Transform::identity())) | ||||
|             .with_children(|parent| { | ||||
|                 parent | ||||
|                     .spawn((Translation::new(0.0, 2.0, 0.0), Transform::identity())) | ||||
|                     .for_current_entity(|entity| children.push(entity)) | ||||
|                     .spawn((Translation::new(0.0, 0.0, 3.0), Transform::identity())) | ||||
|                     .for_current_entity(|entity| children.push(entity)); | ||||
|             }); | ||||
|         commands.apply(&mut world, &mut resources); | ||||
|         schedule.run(&mut world, &mut resources); | ||||
| 
 | ||||
|         assert_eq!( | ||||
|             world.get::<Transform>(children[0]).unwrap().value, | ||||
|             Mat4::from_translation(Vec3::new(1.0, 0.0, 0.0)) | ||||
|                 * Mat4::from_translation(Vec3::new(0.0, 2.0, 0.0)) | ||||
|         ); | ||||
| 
 | ||||
|         assert_eq!( | ||||
|             world.get::<Transform>(children[1]).unwrap().value, | ||||
|             Mat4::from_translation(Vec3::new(1.0, 0.0, 0.0)) | ||||
|                 * Mat4::from_translation(Vec3::new(0.0, 0.0, 3.0)) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -32,7 +32,8 @@ pub struct UiPlugin; | ||||
| impl AppPlugin for UiPlugin { | ||||
|     fn build(&self, app: &mut AppBuilder) { | ||||
|         app.add_system_to_stage(stage::PRE_UPDATE, ui_focus_system.system()) | ||||
|             .add_system_to_stage(stage::POST_UPDATE, ui_update_system.system()) | ||||
|             // must run before transform update systems
 | ||||
|             .add_system_to_stage_front(stage::POST_UPDATE, ui_update_system.system()) | ||||
|             .add_system_to_stage(stage::POST_UPDATE, widget::text_system.system()) | ||||
|             .add_system_to_stage(bevy_render::stage::DRAW, widget::draw_text_system.system()); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Carter Anderson
						Carter Anderson