 a304fd9a99
			
		
	
	
		a304fd9a99
		
	
	
	
	
		
			
			# Objective - Hierarchy tools are not just used for `Transform`: they are also used for scenes. - In the future there's interest in using them for other features, such as visiibility inheritance. - The fact that these tools are found in `bevy_transform` causes a great deal of user and developer confusion - Fixes #2758. ## Solution - Split `bevy_transform` into two! - Make everything work again. Note that this is a very tightly scoped PR: I *know* there are code quality and docs issues that existed in bevy_transform that I've just moved around. We should fix those in a seperate PR and try to merge this ASAP to reduce the bitrot involved in splitting an entire crate. ## Frustrations The API around `GlobalTransform` is a mess: we have massive code and docs duplication, no link between the two types and no clear way to extend this to other forms of inheritance. In the medium-term, I feel pretty strongly that `GlobalTransform` should be replaced by something like `Inherited<Transform>`, which lives in `bevy_hierarchy`: - avoids code duplication - makes the inheritance pattern extensible - links the types at the type-level - allows us to remove all references to inheritance from `bevy_transform`, making it more useful as a standalone crate and cleaning up its docs ## Additional context - double-blessed by @cart in https://github.com/bevyengine/bevy/issues/4141#issuecomment-1063592414 and https://github.com/bevyengine/bevy/issues/2758#issuecomment-913810963 - preparation for more advanced / cleaner hierarchy tools: go read https://github.com/bevyengine/rfcs/pull/53 ! - originally attempted by @finegeometer in #2789. It was a great idea, just needed more discussion! Co-authored-by: Carter Anderson <mcanders1@gmail.com>
		
			
				
	
	
		
			73 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			73 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use crate::components::*;
 | |
| use bevy_ecs::{
 | |
|     entity::Entity,
 | |
|     prelude::Changed,
 | |
|     query::Without,
 | |
|     system::{Commands, Query},
 | |
| };
 | |
| use bevy_utils::HashMap;
 | |
| use smallvec::SmallVec;
 | |
| 
 | |
| /// Updates parents when the hierarchy is changed
 | |
| pub fn parent_update_system(
 | |
|     mut commands: Commands,
 | |
|     removed_parent_query: Query<(Entity, &PreviousParent), Without<Parent>>,
 | |
|     mut parent_query: Query<(Entity, &Parent, Option<&mut PreviousParent>), Changed<Parent>>,
 | |
|     mut children_query: Query<&mut Children>,
 | |
| ) {
 | |
|     // Entities with a missing `Parent` (ie. ones that have a `PreviousParent`), remove
 | |
|     // them from the `Children` of the `PreviousParent`.
 | |
|     for (entity, previous_parent) in removed_parent_query.iter() {
 | |
|         if let Ok(mut previous_parent_children) = children_query.get_mut(previous_parent.0) {
 | |
|             previous_parent_children.0.retain(|e| *e != entity);
 | |
|             commands.entity(entity).remove::<PreviousParent>();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Tracks all newly created `Children` Components this frame.
 | |
|     let mut children_additions = HashMap::<Entity, SmallVec<[Entity; 8]>>::default();
 | |
| 
 | |
|     // Entities with a changed Parent (that also have a PreviousParent, even if None)
 | |
|     for (entity, parent, possible_previous_parent) in parent_query.iter_mut() {
 | |
|         if let Some(mut previous_parent) = possible_previous_parent {
 | |
|             // New and previous point to the same Entity, carry on, nothing to see here.
 | |
|             if previous_parent.0 == parent.0 {
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             // Remove from `PreviousParent.Children`.
 | |
|             if let Ok(mut previous_parent_children) = children_query.get_mut(previous_parent.0) {
 | |
|                 (*previous_parent_children).0.retain(|e| *e != entity);
 | |
|             }
 | |
| 
 | |
|             // Set `PreviousParent = Parent`.
 | |
|             *previous_parent = PreviousParent(parent.0);
 | |
|         } else {
 | |
|             commands.entity(entity).insert(PreviousParent(parent.0));
 | |
|         };
 | |
| 
 | |
|         // Add to the parent's `Children` (either the real component, or
 | |
|         // `children_additions`).
 | |
|         if let Ok(mut new_parent_children) = children_query.get_mut(parent.0) {
 | |
|             // This is the parent
 | |
|             // PERF: Ideally we shouldn't need to check for duplicates
 | |
|             if !(*new_parent_children).0.contains(&entity) {
 | |
|                 (*new_parent_children).0.push(entity);
 | |
|             }
 | |
|         } else {
 | |
|             // The parent doesn't have a children entity, lets add it
 | |
|             children_additions
 | |
|                 .entry(parent.0)
 | |
|                 .or_insert_with(Default::default)
 | |
|                 .push(entity);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Flush the `children_additions` to the command buffer. It is stored separate to
 | |
|     // collect multiple new children that point to the same parent into the same
 | |
|     // SmallVec, and to prevent redundant add+remove operations.
 | |
|     children_additions.iter().for_each(|(e, v)| {
 | |
|         commands.entity(*e).insert(Children::with(v));
 | |
|     });
 | |
| }
 |