fmc/bevy_extensions/f64_transform/
mod.rs

1#![warn(missing_docs)]
2/// The basic components of the transform crate
3mod components;
4mod systems;
5
6use bevy::hierarchy::ValidParentCheckPlugin;
7use bevy::prelude::*;
8pub use components::{GlobalTransform, Transform};
9
10/// A [`Bundle`] of the [`Transform`] and [`GlobalTransform`]
11/// [`Component`](bevy_ecs::component::Component)s, which describe the position of an entity.
12///
13/// * To place or move an entity, you should set its [`Transform`].
14/// * To get the global transform of an entity, you should get its [`GlobalTransform`].
15/// * For transform hierarchies to work correctly, you must have both a [`Transform`] and a [`GlobalTransform`].
16///   * You may use the [`TransformBundle`] to guarantee this.
17///
18/// ## [`Transform`] and [`GlobalTransform`]
19///
20/// [`Transform`] is the position of an entity relative to its parent position, or the reference
21/// frame if it doesn't have a parent.
22///
23/// [`GlobalTransform`] is the position of an entity relative to the reference frame.
24///
25/// [`GlobalTransform`] is updated from [`Transform`] in the system
26/// [`transform_propagate_system`].
27///
28/// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you
29/// update the [`Transform`] of an entity in this stage or after, you will notice a 1 frame lag
30/// before the [`GlobalTransform`] is updated.
31#[derive(Bundle, Clone, Copy, Debug, Default)]
32pub struct TransformBundle {
33    /// The transform of the entity.
34    pub local: Transform,
35    /// The global transform of the entity.
36    pub global: GlobalTransform,
37}
38
39impl TransformBundle {
40    /// An identity [`TransformBundle`] with no translation, rotation, and a scale of 1 on all axes.
41    pub const IDENTITY: Self = TransformBundle {
42        local: Transform::IDENTITY,
43        global: GlobalTransform::IDENTITY,
44    };
45
46    /// Creates a new [`TransformBundle`] from a [`Transform`].
47    ///
48    /// This initializes [`GlobalTransform`] as identity, to be updated later by the
49    /// [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate) stage.
50    #[inline]
51    pub const fn from_transform(transform: Transform) -> Self {
52        TransformBundle {
53            local: transform,
54            ..Self::IDENTITY
55        }
56    }
57}
58
59impl From<Transform> for TransformBundle {
60    #[inline]
61    fn from(transform: Transform) -> Self {
62        Self::from_transform(transform)
63    }
64}
65/// Label enum for the systems relating to transform propagation
66#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
67pub enum TransformSystem {
68    /// Propagates changes in transform to children's [`GlobalTransform`](crate::components::GlobalTransform)
69    TransformPropagate,
70}
71
72/// The base plugin for handling [`Transform`] components
73#[derive(Default)]
74pub struct TransformPlugin;
75
76impl Plugin for TransformPlugin {
77    fn build(&self, app: &mut App) {
78        // A set for `propagate_transforms` to mark it as ambiguous with `sync_simple_transforms`.
79        // Used instead of the `SystemTypeSet` as that would not allow multiple instances of the system.
80        #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
81        struct PropagateTransformsSet;
82
83        app.register_type::<Transform>()
84            .register_type::<GlobalTransform>()
85            .add_plugins(ValidParentCheckPlugin::<GlobalTransform>::default())
86            .configure_sets(
87                PostStartup,
88                PropagateTransformsSet.in_set(TransformSystem::TransformPropagate),
89            )
90            // add transform systems to startup so the first update is "correct"
91            .add_systems(
92                PostStartup,
93                (
94                    systems::sync_simple_transforms
95                        .in_set(TransformSystem::TransformPropagate)
96                        // FIXME: https://github.com/bevyengine/bevy/issues/4381
97                        // These systems cannot access the same entities,
98                        // due to subtle query filtering that is not yet correctly computed in the ambiguity detector
99                        .ambiguous_with(PropagateTransformsSet),
100                    systems::propagate_transforms.in_set(PropagateTransformsSet),
101                ),
102            )
103            .configure_sets(
104                PostUpdate,
105                PropagateTransformsSet.in_set(TransformSystem::TransformPropagate),
106            )
107            .add_systems(
108                PostUpdate,
109                (
110                    systems::sync_simple_transforms
111                        .in_set(TransformSystem::TransformPropagate)
112                        .ambiguous_with(PropagateTransformsSet),
113                    systems::propagate_transforms.in_set(PropagateTransformsSet),
114                ),
115            );
116    }
117}