Expand description
Checks for systems added to the FixedUpdate
schedule that mutably query entities with a
Camera
component.
§Motivation
Modifying the camera in FixedUpdate
can cause jittery, inconsistent, or laggy visuals because
FixedUpdate
may not run every render frame, especially on games with a high FPS.
§Known Issues
This lint only detects systems that explicitly use the With<Camera>
query filter.
§Example
fn move_camera(mut query: Query<&mut Transform, With<Camera>>) {
// ...
}
fn main() {
App::new()
// Uh oh! This could cause issues because the camera may not move every frame!
.add_systems(FixedUpdate, move_camera);
}
Use instead:
fn move_camera(mut query: Query<&mut Transform, With<Camera>>) {
// ...
}
fn main() {
App::new()
// Much better. This will run every frame.
.add_systems(Update, move_camera);
}
Any system that modifies the camera in a user-visible way should be run every render frame. The
Update
schedule is a good choice for this, but it notably runs after FixedUpdate
. You can
use the RunFixedMainLoop
schedule with the RunFixedMainLoopSystem::BeforeFixedMainLoop
system set to run a system before FixedUpdate
:
fn rotate_camera(mut query: Query<&mut Transform, With<Camera>>) {
// ...
}
fn main() {
App::new()
// In 3D games it is common for the player to move in the direction of the camera.
// Because of this, we must rotate the camera before running the physics logic in
// `FixedUpdate`. This will still run every render frame, though, so there won't be any
// lag!
.add_systems(
RunFixedMainLoop,
rotate_camera.in_set(RunFixedMainLoopSystem::BeforeFixedMainLoop),
);
}
For more information, check out the physics in fixed timestep example.