//! Extension to [`EntityCommands`] to modify [`bevy_ecs::hierarchy`] hierarchies.1//! while preserving [`GlobalTransform`].23use crate::prelude::{GlobalTransform, Transform};4use bevy_ecs::{entity::Entity, hierarchy::ChildOf, system::EntityCommands, world::EntityWorldMut};56/// Collection of methods similar to the built-in parenting methods on [`EntityWorldMut`] and [`EntityCommands`], but preserving each7/// entity's [`GlobalTransform`].8pub trait BuildChildrenTransformExt {9/// Change this entity's parent while preserving this entity's [`GlobalTransform`]10/// by updating its [`Transform`].11///12/// Insert the [`ChildOf`] component directly if you don't want to also update the [`Transform`].13///14/// Note that both the hierarchy and transform updates will only execute15/// the next time commands are applied16/// (during [`ApplyDeferred`](bevy_ecs::schedule::ApplyDeferred)).17fn set_parent_in_place(&mut self, parent: Entity) -> &mut Self;1819/// Make this entity parentless while preserving this entity's [`GlobalTransform`]20/// by updating its [`Transform`] to be equal to its current [`GlobalTransform`].21///22/// See [`EntityWorldMut::remove::<ChildOf>`] or [`EntityCommands::remove::<ChildOf>`] for a method that doesn't update the [`Transform`].23///24/// Note that both the hierarchy and transform updates will only execute25/// the next time commands are applied26/// (during [`ApplyDeferred`](bevy_ecs::schedule::ApplyDeferred)).27fn remove_parent_in_place(&mut self) -> &mut Self;28}2930impl BuildChildrenTransformExt for EntityCommands<'_> {31fn set_parent_in_place(&mut self, parent: Entity) -> &mut Self {32self.queue(move |mut entity: EntityWorldMut| {33entity.set_parent_in_place(parent);34})35}3637fn remove_parent_in_place(&mut self) -> &mut Self {38self.queue(move |mut entity: EntityWorldMut| {39entity.remove_parent_in_place();40})41}42}4344impl BuildChildrenTransformExt for EntityWorldMut<'_> {45fn set_parent_in_place(&mut self, parent: Entity) -> &mut Self {46// FIXME: Replace this closure with a `try` block. See: https://github.com/rust-lang/rust/issues/31436.47let mut update_transform = || {48let child = self.id();49let parent_global = self.world_scope(|world| {50world51.get_entity_mut(parent)52.ok()?53.add_child(child)54.get::<GlobalTransform>()55.copied()56})?;57let child_global = self.get::<GlobalTransform>()?;58let new_child_local = child_global.reparented_to(&parent_global);59let mut child_local = self.get_mut::<Transform>()?;60*child_local = new_child_local;61Some(())62};63update_transform();64self65}6667fn remove_parent_in_place(&mut self) -> &mut Self {68self.remove::<ChildOf>();69// FIXME: Replace this closure with a `try` block. See: https://github.com/rust-lang/rust/issues/31436.70let mut update_transform = || {71let global = self.get::<GlobalTransform>()?;72let new_local = global.compute_transform();73let mut local = self.get_mut::<Transform>()?;74*local = new_local;75Some(())76};77update_transform();78self79}80}818283