Support Warning
WebGPU is currently only supported on Chrome starting with version 113, and only on desktop. If they don't work on your configuration, you can check the WebGL2 examples here.//! This example shows how to properly handle player input,
//! advance a physics simulation in a fixed timestep, and display the results.
//!
//! The classic source for how and why this is done is Glenn Fiedler's article
//! [Fix Your Timestep!](https://gafferongames.com/post/fix_your_timestep/).
//! For a more Bevy-centric source, see
//! [this cheatbook entry](https://bevy-cheatbook.github.io/fundamentals/fixed-timestep.html).
//!
//! ## Motivation
//!
//! The naive way of moving a player is to just update their position like so:
//! ```no_run
//! transform.translation += velocity;
//! ```
//! The issue here is that the player's movement speed will be tied to the frame rate.
//! Faster machines will move the player faster, and slower machines will move the player slower.
//! In fact, you can observe this today when running some old games that did it this way on modern hardware!
//! The player will move at a breakneck pace.
//!
//! The more sophisticated way is to update the player's position based on the time that has passed:
//! ```no_run
//! transform.translation += velocity * time.delta_secs();
//! ```
//! This way, velocity represents a speed in units per second, and the player will move at the same speed
//! regardless of the frame rate.
//!
//! However, this can still be problematic if the frame rate is very low or very high.
//! If the frame rate is very low, the player will move in large jumps. This may lead to
//! a player moving in such large jumps that they pass through walls or other obstacles.
//! In general, you cannot expect a physics simulation to behave nicely with *any* delta time.
//! Ideally, we want to have some stability in what kinds of delta times we feed into our physics simulation.
//!
//! The solution is using a fixed timestep. This means that we advance the physics simulation by a fixed amount
//! at a time. If the real time that passed between two frames is less than the fixed timestep, we simply
//! don't advance the physics simulation at all.
//! If it is more, we advance the physics simulation multiple times until we catch up.
//! You can read more about how Bevy implements this in the documentation for
//! [`bevy::time::Fixed`](https://docs.rs/bevy/latest/bevy/time/struct.Fixed.html).
//!
//! This leaves us with a last problem, however. If our physics simulation may advance zero or multiple times
//! per frame, there may be frames in which the player's position did not need to be updated at all,
//! and some where it is updated by a large amount that resulted from running the physics simulation multiple times.
//! This is physically correct, but visually jarring. Imagine a player moving in a straight line, but depending on the frame rate,
//! they may sometimes advance by a large amount and sometimes not at all. Visually, we want the player to move smoothly.
//! This is why we need to separate the player's position in the physics simulation from the player's position in the visual representation.
//! The visual representation can then be interpolated smoothly based on the previous and current actual player position in the physics simulation.
//!
//! This is a tradeoff: every visual frame is now slightly lagging behind the actual physical frame,
//! but in return, the player's movement will appear smooth.
//! There are other ways to compute the visual representation of the player, such as extrapolation.
//! See the [documentation of the lightyear crate](https://cbournhonesque.github.io/lightyear/book/concepts/advanced_replication/visual_interpolation.html)
//! for a nice overview of the different methods and their respective tradeoffs.
//!
//! ## Implementation
//!
//! - The player's inputs since the last physics update are stored in the `AccumulatedInput` component.
//! - The player's velocity is stored in a `Velocity` component. This is the speed in units per second.
//! - The player's current position in the physics simulation is stored in a `PhysicalTranslation` component.
//! - The player's previous position in the physics simulation is stored in a `PreviousPhysicalTranslation` component.
//! - The player's visual representation is stored in Bevy's regular `Transform` component.
//! - Every frame, we go through the following steps:
//! - Accumulate the player's input and set the current speed in the `handle_input` system.
//! This is run in the `RunFixedMainLoop` schedule, ordered in `RunFixedMainLoopSystem::BeforeFixedMainLoop`,
//! which runs before the fixed timestep loop. This is run every frame.
//! - Advance the physics simulation by one fixed timestep in the `advance_physics` system.
//! Accumulated input is consumed here.
//! This is run in the `FixedUpdate` schedule, which runs zero or multiple times per frame.
//! - Update the player's visual representation in the `interpolate_rendered_transform` system.
//! This interpolates between the player's previous and current position in the physics simulation.
//! It is run in the `RunFixedMainLoop` schedule, ordered in `RunFixedMainLoopSystem::AfterFixedMainLoop`,
//! which runs after the fixed timestep loop. This is run every frame.
//!
//!
//! ## Controls
//!
//! | Key Binding | Action |
//! |:---------------------|:--------------|
//! | `W` | Move up |
//! | `S` | Move down |
//! | `A` | Move left |
//! | `D` | Move right |
use *;
/// A vector representing the player's input, accumulated over all frames that ran
/// since the last time the physics simulation was advanced.
;
/// A vector representing the player's velocity in the physics simulation.
;
/// The actual position of the player in the physics simulation.
/// This is separate from the `Transform`, which is merely a visual representation.
///
/// If you want to make sure that this component is always initialized
/// with the same value as the `Transform`'s translation, you can
/// use a [component lifecycle hook](https://docs.rs/bevy/0.14.0/bevy/ecs/component/struct.ComponentHooks.html)
;
/// The value [`PhysicalTranslation`] had in the last fixed timestep.
/// Used for interpolation in the `interpolate_rendered_transform` system.
;
/// Spawn the player sprite and a 2D camera.
/// Spawn a bit of UI text to explain how to move the player.
/// Handle keyboard input and accumulate it in the `AccumulatedInput` component.
///
/// There are many strategies for how to handle all the input that happened since the last fixed timestep.
/// This is a very simple one: we just accumulate the input and average it out by normalizing it.
/// Advance the physics simulation by one fixed timestep. This may run zero or multiple times per frame.
///
/// Note that since this runs in `FixedUpdate`, `Res<Time>` would be `Res<Time<Fixed>>` automatically.
/// We are being explicit here for clarity.