 c92ee31779
			
		
	
	
		c92ee31779
		
			
		
	
	
	
	
		
			
			# Objective - Fixes #14873, see that issue for a whole lot of context ## Solution - Add a blessed system set for this stuff. See [this Discord discussion](https://discord.com/channels/691052431525675048/749335865876021248/1276262931327094908). Note that the gizmo systems, [LWIM](https://github.com/Leafwing-Studios/leafwing-input-manager/pull/522/files#diff-9b59ee4899ad0a5d008889ea89a124a7291316532e42f9f3d6ae842b906fb095R154) and now a new plugin I'm working on are all already ordering against `run_fixed_main_schedule`, so having a dedicated system set should be more robust and hopefully also more discoverable. --- ## ~~Showcase~~ ~~I can add a little video of a smooth camera later if this gets merged :)~~ Apparently a release note is not needed, so I'll leave it out. See the changes in the fixed timestep example for usage showcase and the video in #14873 for a more or less accurate video of the effect (it does not use the same solution though, so it is not quite the same) ## Migration Guide [run_fixed_main_schedule](https://docs.rs/bevy/latest/bevy/time/fn.run_fixed_main_schedule.html) is no longer public. If you used to order against it, use the new dedicated `RunFixedMainLoopSystem` system set instead. You can replace your usage of `run_fixed_main_schedule` one for one by `RunFixedMainLoopSystem::FixedMainLoop`, but it is now more idiomatic to place your systems in either `RunFixedMainLoopSystem::BeforeFixedMainLoop` or `RunFixedMainLoopSystem::AfterFixedMainLoop` Old: ```rust app.add_systems( RunFixedMainLoop, some_system.before(run_fixed_main_schedule) ); ``` New: ```rust app.add_systems( RunFixedMainLoop, some_system.in_set(RunFixedMainLoopSystem::BeforeFixedMainLoop) ); ``` --------- Co-authored-by: Tau Gärtli <git@tau.garden>
		
			
				
	
	
		
			465 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			465 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use crate::{App, Plugin};
 | |
| use bevy_ecs::{
 | |
|     schedule::{
 | |
|         ExecutorKind, InternedScheduleLabel, IntoSystemSetConfigs, Schedule, ScheduleLabel,
 | |
|         SystemSet,
 | |
|     },
 | |
|     system::{Local, Resource},
 | |
|     world::{Mut, World},
 | |
| };
 | |
| 
 | |
| /// The schedule that contains the app logic that is evaluated each tick of [`App::update()`].
 | |
| ///
 | |
| /// By default, it will run the following schedules in the given order:
 | |
| ///
 | |
| /// On the first run of the schedule (and only on the first run), it will run:
 | |
| /// * [`PreStartup`]
 | |
| /// * [`Startup`]
 | |
| /// * [`PostStartup`]
 | |
| ///
 | |
| /// Then it will run:
 | |
| /// * [`First`]
 | |
| /// * [`PreUpdate`]
 | |
| /// * [`StateTransition`]
 | |
| /// * [`RunFixedMainLoop`]
 | |
| ///     * This will run [`FixedMain`] zero to many times, based on how much time has elapsed.
 | |
| /// * [`Update`]
 | |
| /// * [`PostUpdate`]
 | |
| /// * [`Last`]
 | |
| ///
 | |
| /// # Rendering
 | |
| ///
 | |
| /// Note rendering is not executed in the main schedule by default.
 | |
| /// Instead, rendering is performed in a separate [`SubApp`]
 | |
| /// which exchanges data with the main app in between the main schedule runs.
 | |
| ///
 | |
| /// See [`RenderPlugin`] and [`PipelinedRenderingPlugin`] for more details.
 | |
| ///
 | |
| /// [`StateTransition`]: https://docs.rs/bevy/latest/bevy/prelude/struct.StateTransition.html
 | |
| /// [`RenderPlugin`]: https://docs.rs/bevy/latest/bevy/render/struct.RenderPlugin.html
 | |
| /// [`PipelinedRenderingPlugin`]: https://docs.rs/bevy/latest/bevy/render/pipelined_rendering/struct.PipelinedRenderingPlugin.html
 | |
| /// [`SubApp`]: crate::SubApp
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct Main;
 | |
| 
 | |
| /// The schedule that runs before [`Startup`].
 | |
| ///
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct PreStartup;
 | |
| 
 | |
| /// The schedule that runs once when the app starts.
 | |
| ///
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct Startup;
 | |
| 
 | |
| /// The schedule that runs once after [`Startup`].
 | |
| ///
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct PostStartup;
 | |
| 
 | |
| /// Runs first in the schedule.
 | |
| ///
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct First;
 | |
| 
 | |
| /// The schedule that contains logic that must run before [`Update`]. For example, a system that reads raw keyboard
 | |
| /// input OS events into an `Events` resource. This enables systems in [`Update`] to consume the events from the `Events`
 | |
| /// resource without actually knowing about (or taking a direct scheduler dependency on) the "os-level keyboard event system".
 | |
| ///
 | |
| /// [`PreUpdate`] exists to do "engine/plugin preparation work" that ensures the APIs consumed in [`Update`] are "ready".
 | |
| /// [`PreUpdate`] abstracts out "pre work implementation details".
 | |
| ///
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct PreUpdate;
 | |
| 
 | |
| /// Runs the [`FixedMain`] schedule in a loop according until all relevant elapsed time has been "consumed".
 | |
| /// If you need to order your variable timestep systems
 | |
| /// before or after the fixed update logic, use the [`RunFixedMainLoopSystem`] system set.
 | |
| ///
 | |
| /// Note that in contrast to most other Bevy schedules, systems added directly to
 | |
| /// [`RunFixedMainLoop`] will *not* be parallelized between each other.
 | |
| ///
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct RunFixedMainLoop;
 | |
| 
 | |
| /// Runs first in the [`FixedMain`] schedule.
 | |
| ///
 | |
| /// See the [`FixedMain`] schedule for details on how fixed updates work.
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct FixedFirst;
 | |
| 
 | |
| /// The schedule that contains logic that must run before [`FixedUpdate`].
 | |
| ///
 | |
| /// See the [`FixedMain`] schedule for details on how fixed updates work.
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct FixedPreUpdate;
 | |
| 
 | |
| /// The schedule that contains most gameplay logic, which runs at a fixed rate rather than every render frame.
 | |
| /// For logic that should run once per render frame, use the [`Update`] schedule instead.
 | |
| ///
 | |
| /// Examples of systems that should run at a fixed rate include (but are not limited to):
 | |
| /// - Physics
 | |
| /// - AI
 | |
| /// - Networking
 | |
| /// - Game rules
 | |
| ///
 | |
| /// See the [`Update`] schedule for examples of systems that *should not* use this schedule.
 | |
| /// See the [`FixedMain`] schedule for details on how fixed updates work.
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct FixedUpdate;
 | |
| 
 | |
| /// The schedule that runs after the [`FixedUpdate`] schedule, for reacting
 | |
| /// to changes made in the main update logic.
 | |
| ///
 | |
| /// See the [`FixedMain`] schedule for details on how fixed updates work.
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct FixedPostUpdate;
 | |
| 
 | |
| /// The schedule that runs last in [`FixedMain`]
 | |
| ///
 | |
| /// See the [`FixedMain`] schedule for details on how fixed updates work.
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct FixedLast;
 | |
| 
 | |
| /// The schedule that contains systems which only run after a fixed period of time has elapsed.
 | |
| ///
 | |
| /// This is run by the [`RunFixedMainLoop`] schedule. If you need to order your variable timestep systems
 | |
| /// before or after the fixed update logic, use the [`RunFixedMainLoopSystem`] system set.
 | |
| ///
 | |
| /// Frequency of execution is configured by inserting `Time<Fixed>` resource, 64 Hz by default.
 | |
| /// See [this example](https://github.com/bevyengine/bevy/blob/latest/examples/time/time.rs).
 | |
| ///
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct FixedMain;
 | |
| 
 | |
| /// The schedule that contains any app logic that must run once per render frame.
 | |
| /// For most gameplay logic, consider using [`FixedUpdate`] instead.
 | |
| ///
 | |
| /// Examples of systems that should run once per render frame include (but are not limited to):
 | |
| /// - UI
 | |
| /// - Input handling
 | |
| /// - Audio control
 | |
| ///
 | |
| /// See the [`FixedUpdate`] schedule for examples of systems that *should not* use this schedule.
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct Update;
 | |
| 
 | |
| /// The schedule that contains scene spawning.
 | |
| ///
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct SpawnScene;
 | |
| 
 | |
| /// The schedule that contains logic that must run after [`Update`]. For example, synchronizing "local transforms" in a hierarchy
 | |
| /// to "global" absolute transforms. This enables the [`PostUpdate`] transform-sync system to react to "local transform" changes in
 | |
| /// [`Update`] without the [`Update`] systems needing to know about (or add scheduler dependencies for) the "global transform sync system".
 | |
| ///
 | |
| /// [`PostUpdate`] exists to do "engine/plugin response work" to things that happened in [`Update`].
 | |
| /// [`PostUpdate`] abstracts out "implementation details" from users defining systems in [`Update`].
 | |
| ///
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct PostUpdate;
 | |
| 
 | |
| /// Runs last in the schedule.
 | |
| ///
 | |
| /// See the [`Main`] schedule for some details about how schedules are run.
 | |
| #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
 | |
| pub struct Last;
 | |
| 
 | |
| /// Defines the schedules to be run for the [`Main`] schedule, including
 | |
| /// their order.
 | |
| #[derive(Resource, Debug)]
 | |
| pub struct MainScheduleOrder {
 | |
|     /// The labels to run for the main phase of the [`Main`] schedule (in the order they will be run).
 | |
|     pub labels: Vec<InternedScheduleLabel>,
 | |
|     /// The labels to run for the startup phase of the [`Main`] schedule (in the order they will be run).
 | |
|     pub startup_labels: Vec<InternedScheduleLabel>,
 | |
| }
 | |
| 
 | |
| impl Default for MainScheduleOrder {
 | |
|     fn default() -> Self {
 | |
|         Self {
 | |
|             labels: vec![
 | |
|                 First.intern(),
 | |
|                 PreUpdate.intern(),
 | |
|                 RunFixedMainLoop.intern(),
 | |
|                 Update.intern(),
 | |
|                 SpawnScene.intern(),
 | |
|                 PostUpdate.intern(),
 | |
|                 Last.intern(),
 | |
|             ],
 | |
|             startup_labels: vec![PreStartup.intern(), Startup.intern(), PostStartup.intern()],
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl MainScheduleOrder {
 | |
|     /// Adds the given `schedule` after the `after` schedule in the main list of schedules.
 | |
|     pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) {
 | |
|         let index = self
 | |
|             .labels
 | |
|             .iter()
 | |
|             .position(|current| (**current).eq(&after))
 | |
|             .unwrap_or_else(|| panic!("Expected {after:?} to exist"));
 | |
|         self.labels.insert(index + 1, schedule.intern());
 | |
|     }
 | |
| 
 | |
|     /// Adds the given `schedule` before the `before` schedule in the main list of schedules.
 | |
|     pub fn insert_before(&mut self, before: impl ScheduleLabel, schedule: impl ScheduleLabel) {
 | |
|         let index = self
 | |
|             .labels
 | |
|             .iter()
 | |
|             .position(|current| (**current).eq(&before))
 | |
|             .unwrap_or_else(|| panic!("Expected {before:?} to exist"));
 | |
|         self.labels.insert(index, schedule.intern());
 | |
|     }
 | |
| 
 | |
|     /// Adds the given `schedule` after the `after` schedule in the list of startup schedules.
 | |
|     pub fn insert_startup_after(
 | |
|         &mut self,
 | |
|         after: impl ScheduleLabel,
 | |
|         schedule: impl ScheduleLabel,
 | |
|     ) {
 | |
|         let index = self
 | |
|             .startup_labels
 | |
|             .iter()
 | |
|             .position(|current| (**current).eq(&after))
 | |
|             .unwrap_or_else(|| panic!("Expected {after:?} to exist"));
 | |
|         self.startup_labels.insert(index + 1, schedule.intern());
 | |
|     }
 | |
| 
 | |
|     /// Adds the given `schedule` before the `before` schedule in the list of startup schedules.
 | |
|     pub fn insert_startup_before(
 | |
|         &mut self,
 | |
|         before: impl ScheduleLabel,
 | |
|         schedule: impl ScheduleLabel,
 | |
|     ) {
 | |
|         let index = self
 | |
|             .startup_labels
 | |
|             .iter()
 | |
|             .position(|current| (**current).eq(&before))
 | |
|             .unwrap_or_else(|| panic!("Expected {before:?} to exist"));
 | |
|         self.startup_labels.insert(index, schedule.intern());
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Main {
 | |
|     /// A system that runs the "main schedule"
 | |
|     pub fn run_main(world: &mut World, mut run_at_least_once: Local<bool>) {
 | |
|         if !*run_at_least_once {
 | |
|             world.resource_scope(|world, order: Mut<MainScheduleOrder>| {
 | |
|                 for &label in &order.startup_labels {
 | |
|                     let _ = world.try_run_schedule(label);
 | |
|                 }
 | |
|             });
 | |
|             *run_at_least_once = true;
 | |
|         }
 | |
| 
 | |
|         world.resource_scope(|world, order: Mut<MainScheduleOrder>| {
 | |
|             for &label in &order.labels {
 | |
|                 let _ = world.try_run_schedule(label);
 | |
|             }
 | |
|         });
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Initializes the [`Main`] schedule, sub schedules, and resources for a given [`App`].
 | |
| pub struct MainSchedulePlugin;
 | |
| 
 | |
| impl Plugin for MainSchedulePlugin {
 | |
|     fn build(&self, app: &mut App) {
 | |
|         // simple "facilitator" schedules benefit from simpler single threaded scheduling
 | |
|         let mut main_schedule = Schedule::new(Main);
 | |
|         main_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
 | |
|         let mut fixed_main_schedule = Schedule::new(FixedMain);
 | |
|         fixed_main_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
 | |
|         let mut fixed_main_loop_schedule = Schedule::new(RunFixedMainLoop);
 | |
|         fixed_main_loop_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
 | |
| 
 | |
|         app.add_schedule(main_schedule)
 | |
|             .add_schedule(fixed_main_schedule)
 | |
|             .add_schedule(fixed_main_loop_schedule)
 | |
|             .init_resource::<MainScheduleOrder>()
 | |
|             .init_resource::<FixedMainScheduleOrder>()
 | |
|             .add_systems(Main, Main::run_main)
 | |
|             .add_systems(FixedMain, FixedMain::run_fixed_main)
 | |
|             .configure_sets(
 | |
|                 RunFixedMainLoop,
 | |
|                 (
 | |
|                     RunFixedMainLoopSystem::BeforeFixedMainLoop,
 | |
|                     RunFixedMainLoopSystem::FixedMainLoop,
 | |
|                     RunFixedMainLoopSystem::AfterFixedMainLoop,
 | |
|                 )
 | |
|                     .chain(),
 | |
|             );
 | |
| 
 | |
|         #[cfg(feature = "bevy_debug_stepping")]
 | |
|         {
 | |
|             use bevy_ecs::schedule::{IntoSystemConfigs, Stepping};
 | |
|             app.add_systems(Main, Stepping::begin_frame.before(Main::run_main));
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Defines the schedules to be run for the [`FixedMain`] schedule, including
 | |
| /// their order.
 | |
| #[derive(Resource, Debug)]
 | |
| pub struct FixedMainScheduleOrder {
 | |
|     /// The labels to run for the [`FixedMain`] schedule (in the order they will be run).
 | |
|     pub labels: Vec<InternedScheduleLabel>,
 | |
| }
 | |
| 
 | |
| impl Default for FixedMainScheduleOrder {
 | |
|     fn default() -> Self {
 | |
|         Self {
 | |
|             labels: vec![
 | |
|                 FixedFirst.intern(),
 | |
|                 FixedPreUpdate.intern(),
 | |
|                 FixedUpdate.intern(),
 | |
|                 FixedPostUpdate.intern(),
 | |
|                 FixedLast.intern(),
 | |
|             ],
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl FixedMainScheduleOrder {
 | |
|     /// Adds the given `schedule` after the `after` schedule
 | |
|     pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) {
 | |
|         let index = self
 | |
|             .labels
 | |
|             .iter()
 | |
|             .position(|current| (**current).eq(&after))
 | |
|             .unwrap_or_else(|| panic!("Expected {after:?} to exist"));
 | |
|         self.labels.insert(index + 1, schedule.intern());
 | |
|     }
 | |
| 
 | |
|     /// Adds the given `schedule` before the `before` schedule
 | |
|     pub fn insert_before(&mut self, before: impl ScheduleLabel, schedule: impl ScheduleLabel) {
 | |
|         let index = self
 | |
|             .labels
 | |
|             .iter()
 | |
|             .position(|current| (**current).eq(&before))
 | |
|             .unwrap_or_else(|| panic!("Expected {before:?} to exist"));
 | |
|         self.labels.insert(index, schedule.intern());
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl FixedMain {
 | |
|     /// A system that runs the fixed timestep's "main schedule"
 | |
|     pub fn run_fixed_main(world: &mut World) {
 | |
|         world.resource_scope(|world, order: Mut<FixedMainScheduleOrder>| {
 | |
|             for &label in &order.labels {
 | |
|                 let _ = world.try_run_schedule(label);
 | |
|             }
 | |
|         });
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Set enum for the systems that want to run inside [`RunFixedMainLoop`],
 | |
| /// but before or after the fixed update logic. Systems in this set
 | |
| /// will run exactly once per frame, regardless of the number of fixed updates.
 | |
| /// They will also run under a variable timestep.
 | |
| ///
 | |
| /// This is useful for handling things that need to run every frame, but
 | |
| /// also need to be read by the fixed update logic. See the individual variants
 | |
| /// for examples of what kind of systems should be placed in each.
 | |
| ///
 | |
| /// Note that in contrast to most other Bevy schedules, systems added directly to
 | |
| /// [`RunFixedMainLoop`] will *not* be parallelized between each other.
 | |
| #[derive(Debug, Hash, PartialEq, Eq, Copy, Clone, SystemSet)]
 | |
| pub enum RunFixedMainLoopSystem {
 | |
|     /// Runs before the fixed update logic.
 | |
|     ///
 | |
|     /// A good example of a system that fits here
 | |
|     /// is camera movement, which needs to be updated in a variable timestep,
 | |
|     /// as you want the camera to move with as much precision and updates as
 | |
|     /// the frame rate allows. A physics system that needs to read the camera
 | |
|     /// position and orientation, however, should run in the fixed update logic,
 | |
|     /// as it needs to be deterministic and run at a fixed rate for better stability.
 | |
|     /// Note that we are not placing the camera movement system in `Update`, as that
 | |
|     /// would mean that the physics system already ran at that point.
 | |
|     ///
 | |
|     /// # Example
 | |
|     /// ```
 | |
|     /// # use bevy_app::prelude::*;
 | |
|     /// # use bevy_ecs::prelude::*;
 | |
|     /// App::new()
 | |
|     ///   .add_systems(
 | |
|     ///     RunFixedMainLoop,
 | |
|     ///     update_camera_rotation.in_set(RunFixedMainLoopSystem::BeforeFixedMainLoop))
 | |
|     ///   .add_systems(FixedUpdate, update_physics);
 | |
|     ///
 | |
|     /// # fn update_camera_rotation() {}
 | |
|     /// # fn update_physics() {}
 | |
|     /// ```
 | |
|     BeforeFixedMainLoop,
 | |
|     /// Contains the fixed update logic.
 | |
|     /// Runs [`FixedMain`] zero or more times based on delta of
 | |
|     /// [`Time<Virtual>`] and [`Time::overstep`].
 | |
|     ///
 | |
|     /// Don't place systems here, use [`FixedUpdate`] and friends instead.
 | |
|     /// Use this system instead to order your systems to run specifically inbetween the fixed update logic and all
 | |
|     /// other systems that run in [`RunFixedMainLoopSystem::BeforeFixedMainLoop`] or [`RunFixedMainLoopSystem::AfterFixedMainLoop`].
 | |
|     ///
 | |
|     /// [`Time<Virtual>`]: https://docs.rs/bevy/latest/bevy/prelude/struct.Virtual.html
 | |
|     /// [`Time::overstep`]: https://docs.rs/bevy/latest/bevy/time/struct.Time.html#method.overstep
 | |
|     /// # Example
 | |
|     /// ```
 | |
|     /// # use bevy_app::prelude::*;
 | |
|     /// # use bevy_ecs::prelude::*;
 | |
|     /// App::new()
 | |
|     ///   .add_systems(FixedUpdate, update_physics)
 | |
|     ///   .add_systems(
 | |
|     ///     RunFixedMainLoop,
 | |
|     ///     (
 | |
|     ///       // This system will be called before all interpolation systems
 | |
|     ///       // that third-party plugins might add.
 | |
|     ///       prepare_for_interpolation
 | |
|     ///         .after(RunFixedMainLoopSystem::FixedMainLoop)
 | |
|     ///         .before(RunFixedMainLoopSystem::AfterFixedMainLoop),
 | |
|     ///     )
 | |
|     ///   );
 | |
|     ///
 | |
|     /// # fn prepare_for_interpolation() {}
 | |
|     /// # fn update_physics() {}
 | |
|     /// ```
 | |
|     FixedMainLoop,
 | |
|     /// Runs after the fixed update logic.
 | |
|     ///
 | |
|     /// A good example of a system that fits here
 | |
|     /// is a system that interpolates the transform of an entity between the last and current fixed update.
 | |
|     /// See the [fixed timestep example] for more details.
 | |
|     ///
 | |
|     /// [fixed timestep example]: https://github.com/bevyengine/bevy/blob/main/examples/movement/physics_in_fixed_timestep.rs
 | |
|     ///
 | |
|     /// # Example
 | |
|     /// ```
 | |
|     /// # use bevy_app::prelude::*;
 | |
|     /// # use bevy_ecs::prelude::*;
 | |
|     /// App::new()
 | |
|     ///   .add_systems(FixedUpdate, update_physics)
 | |
|     ///   .add_systems(
 | |
|     ///     RunFixedMainLoop,
 | |
|     ///     interpolate_transforms.in_set(RunFixedMainLoopSystem::AfterFixedMainLoop));
 | |
|     ///
 | |
|     /// # fn interpolate_transforms() {}
 | |
|     /// # fn update_physics() {}
 | |
|     /// ```
 | |
|     AfterFixedMainLoop,
 | |
| }
 |