From f12d585d7bfe843ba2792ffbb1a2765a12a590b4 Mon Sep 17 00:00:00 2001 From: Pedro Yudi Honda Date: Thu, 9 Oct 2025 02:17:34 -0300 Subject: [PATCH 01/11] Makes first draft of example, registers example in Cargo.toml and README.md. --- Cargo.toml | 12 +++ examples/README.md | 1 + examples/camera/freecam_controller.rs | 110 ++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 examples/camera/freecam_controller.rs diff --git a/Cargo.toml b/Cargo.toml index 86acffa412df2..b7af76ef58734 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4127,6 +4127,18 @@ description = "A first-person camera that uses a world model and a view model wi category = "Camera" wasm = true +[[example]] +name = "freecam_controller" +path = "examples/camera/freecam_controller.rs" +doc-scrape-examples = true +required-features = ["bevy_camera_controller", "free_cam"] + +[package.metadata.example.freecam_controller] +name = "Freecam camera controller" +description = "A freecam camera controller that showcases its basic features" +category = "Camera" +wasm = true + [[example]] name = "projection_zoom" path = "examples/camera/projection_zoom.rs" diff --git a/examples/README.md b/examples/README.md index 349c6adb965f5..a41590efef426 100644 --- a/examples/README.md +++ b/examples/README.md @@ -285,6 +285,7 @@ Example | Description [Camera Orbit](../examples/camera/camera_orbit.rs) | Shows how to orbit a static scene using pitch, yaw, and roll. [Custom Projection](../examples/camera/custom_projection.rs) | Shows how to create custom camera projections. [First person view model](../examples/camera/first_person_view_model.rs) | A first-person camera that uses a world model and a view model with different field of views (FOV) +[Freecam camera controller](../examples/camera/freecam_controller.rs) | A freecam camera controller that showcases its basic features. [Projection Zoom](../examples/camera/projection_zoom.rs) | Shows how to zoom orthographic and perspective projection cameras. [Screen Shake](../examples/camera/2d_screen_shake.rs) | A simple 2D screen shake effect diff --git a/examples/camera/freecam_controller.rs b/examples/camera/freecam_controller.rs new file mode 100644 index 0000000000000..238a006c60e01 --- /dev/null +++ b/examples/camera/freecam_controller.rs @@ -0,0 +1,110 @@ +//! This example showcases the default freecam camera controller. +//! +//! a + +use std::f32::consts::{FRAC_PI_4, PI}; + +use bevy::{ + camera_controller::free_cam::{FreeCam, FreeCamPlugin}, + color::palettes::tailwind, + prelude::* +}; + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + // Plugin that enables freecam functionality + .add_plugins(FreeCamPlugin) + // Example code plugins + .add_plugins((CameraPlugin, ScenePlugin)) + .run(); +} + +// Plugin that spawns the camera. +struct CameraPlugin; +impl Plugin for CameraPlugin { + fn build(&self, app: &mut App) { + app + .add_systems(Startup, spawn_camera); + } +} + +fn spawn_camera(mut commands: Commands) { + commands.spawn(( + Camera3d::default(), + Transform::from_xyz(0.0, 1.0, 0.0).looking_to(Vec3::X, Vec3::Y), + // This component sotres all camera settings and state, which is used by the FreeCamPlugin to + // control it. These properties can be chagned at runtime, but beware the controller system is + // constantly using and modifying those values unless the enabled field is false. + FreeCam { + sensitivity: 0.1, + walk_speed: 3.0, + run_speed: 9.0, + ..default() + }, + )); +} + +// Plugin that spawns the scene and lighting. +struct ScenePlugin; +impl Plugin for ScenePlugin { + fn build(&self, app: &mut App) { + app + .add_systems( + Startup, + (spawn_lights, spawn_world)); + } +} + +fn spawn_lights(mut commands: Commands) { + commands.spawn(( + PointLight { + color: Color::from(tailwind::ORANGE_100), + shadows_enabled: true, + ..default() + }, + Transform::from_xyz(0.0, 3.0, 0.0), + )); + + commands.spawn(( + PointLight { + color: Color::from(tailwind::RED_800), + shadows_enabled: true, + ..default() + }, + Transform::from_xyz(0.0, -0.5, 0.0), + )); +} + +fn spawn_world( + mut commands: Commands, + mut materials: ResMut>, + mut meshes: ResMut>, +) { + let floor = meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(10.0))); + let cube = meshes.add(Cuboid::new(1.0, 1.0, 1.0)); + + let floor_material = materials.add(Color::WHITE); + + // Top side of floor + commands.spawn(( + Mesh3d(floor.clone()), + MeshMaterial3d(floor_material.clone()), + )); + // Under side of floor + commands.spawn(( + Mesh3d(floor.clone()), + MeshMaterial3d(floor_material.clone()), + Transform::default().with_rotation(Quat::from_rotation_x(PI)) + )); + // Hidden cube under floor + commands.spawn(( + Mesh3d(cube.clone()), + MeshMaterial3d(floor_material.clone()), + Transform { + translation: Vec3::new(0.0, -2.0, 0.0), + rotation: Quat::from_euler(EulerRot::YXZEx, FRAC_PI_4, FRAC_PI_4, 0.0), + ..default() + } + )); +} From e8b6c50e17ef5838409723f97b7c6ef1fe6e525f Mon Sep 17 00:00:00 2001 From: Pedro Yudi Honda Date: Thu, 9 Oct 2025 02:58:43 -0300 Subject: [PATCH 02/11] refines scene and adds example documentation --- examples/camera/freecam_controller.rs | 88 +++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 12 deletions(-) diff --git a/examples/camera/freecam_controller.rs b/examples/camera/freecam_controller.rs index 238a006c60e01..be5023f2f2173 100644 --- a/examples/camera/freecam_controller.rs +++ b/examples/camera/freecam_controller.rs @@ -1,6 +1,38 @@ //! This example showcases the default freecam camera controller. //! -//! a +//! The default freecam controller is useful for exploring large scenes, debugging and editing purposes. To use it, +//! simply add the [`FreeCamPlugin`] to your [`App`] and attatch the [`FreeCam`] component to the camera entity you +//! wish to control. +//! +//! ## Default Controls +//! +//! This controller has a simple 6-axis control scheme, and mouse controls for camera orientation. There are also +//! bindings for capturing the mouse, both while holding the button and toggle, a run feature that increases the +//! max speed, and scrolling changes the movement speed. All keybinds can be changed by editing the [`FreeCam`] +//! component. +//! +//! | Default Key Binding | Action | +//! |:--------------------|:-----------------------| +//! | Mouse | Look around | +//! | Left click | Capture mouse (hold) | +//! | M | Capture mouse (toggle) | +//! | WASD | Horizontal movement | +//! | QE | Vertical movement | +//! | Left shift | Run | +//! | Scroll wheel | Change movement speed | +//! +//! The movement speed, sensitivity and friction can also be changed by the [`FreeCam`] component. +//! +//! ## Example controls +//! +//! This example also provides a few extra keybinds to change the camera sensitivity and friction. +//! +//! | Key Binding | Action | +//! |:------------|:---------------------| +//! | Z | Decrease sensitivity | +//! | X | Increase snsitivity | +//! | C | Decrease friction | +//! | V | Increase friction | use std::f32::consts::{FRAC_PI_4, PI}; @@ -33,7 +65,7 @@ fn spawn_camera(mut commands: Commands) { commands.spawn(( Camera3d::default(), Transform::from_xyz(0.0, 1.0, 0.0).looking_to(Vec3::X, Vec3::Y), - // This component sotres all camera settings and state, which is used by the FreeCamPlugin to + // This component stores all camera settings and state, which is used by the FreeCamPlugin to // control it. These properties can be chagned at runtime, but beware the controller system is // constantly using and modifying those values unless the enabled field is false. FreeCam { @@ -57,18 +89,28 @@ impl Plugin for ScenePlugin { } fn spawn_lights(mut commands: Commands) { + // Main light commands.spawn(( PointLight { - color: Color::from(tailwind::ORANGE_100), + color: Color::from(tailwind::ORANGE_300), shadows_enabled: true, ..default() }, Transform::from_xyz(0.0, 3.0, 0.0), )); - + // Light behind wall commands.spawn(( PointLight { - color: Color::from(tailwind::RED_800), + color: Color::WHITE, + shadows_enabled: true, + ..default() + }, + Transform::from_xyz(-3.5, 3.0, 0.0), + )); + // Light under floor + commands.spawn(( + PointLight { + color: Color::from(tailwind::RED_300), shadows_enabled: true, ..default() }, @@ -81,28 +123,50 @@ fn spawn_world( mut materials: ResMut>, mut meshes: ResMut>, ) { - let floor = meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(10.0))); let cube = meshes.add(Cuboid::new(1.0, 1.0, 1.0)); + let floor = meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(10.0))); + let sphere = meshes.add(Sphere::new(0.5)); + let wall = meshes.add(Cuboid::new(0.2, 4.0, 3.0)); - let floor_material = materials.add(Color::WHITE); + let blue_material = materials.add(Color::from(tailwind::BLUE_700)); + let red_material = materials.add(Color::from(tailwind::RED_950)); + let white_material = materials.add(Color::WHITE); // Top side of floor commands.spawn(( Mesh3d(floor.clone()), - MeshMaterial3d(floor_material.clone()), + MeshMaterial3d(white_material.clone()), )); // Under side of floor commands.spawn(( Mesh3d(floor.clone()), - MeshMaterial3d(floor_material.clone()), - Transform::default().with_rotation(Quat::from_rotation_x(PI)) + MeshMaterial3d(white_material.clone()), + Transform::from_xyz(0.0, -0.01, 0.0).with_rotation(Quat::from_rotation_x(PI)) + )); + // Blue sphere + commands.spawn(( + Mesh3d(sphere.clone()), + MeshMaterial3d(blue_material.clone()), + Transform::from_xyz(3.0, 1.5, 0.0), + )); + // Tall wall + commands.spawn(( + Mesh3d(wall.clone()), + MeshMaterial3d(white_material.clone()), + Transform::from_xyz(-3.0, 2.0, 0.0), + )); + // Cube behind wall + commands.spawn(( + Mesh3d(cube.clone()), + MeshMaterial3d(blue_material.clone()), + Transform::from_xyz(-4.2, 0.5, 0.0), )); // Hidden cube under floor commands.spawn(( Mesh3d(cube.clone()), - MeshMaterial3d(floor_material.clone()), + MeshMaterial3d(red_material.clone()), Transform { - translation: Vec3::new(0.0, -2.0, 0.0), + translation: Vec3::new(3.0, -2.0, 0.0), rotation: Quat::from_euler(EulerRot::YXZEx, FRAC_PI_4, FRAC_PI_4, 0.0), ..default() } From 8bae35b7729bd4d1ed4eabcdc1dbc932a76e7eb6 Mon Sep 17 00:00:00 2001 From: Pedro Yudi Honda Date: Thu, 9 Oct 2025 03:35:18 -0300 Subject: [PATCH 03/11] implements first version with settings control --- examples/camera/freecam_controller.rs | 82 ++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/examples/camera/freecam_controller.rs b/examples/camera/freecam_controller.rs index be5023f2f2173..27c9b802b6981 100644 --- a/examples/camera/freecam_controller.rs +++ b/examples/camera/freecam_controller.rs @@ -48,7 +48,7 @@ fn main() { // Plugin that enables freecam functionality .add_plugins(FreeCamPlugin) // Example code plugins - .add_plugins((CameraPlugin, ScenePlugin)) + .add_plugins((CameraPlugin, CameraSettingsPlugin, ScenePlugin)) .run(); } @@ -69,7 +69,8 @@ fn spawn_camera(mut commands: Commands) { // control it. These properties can be chagned at runtime, but beware the controller system is // constantly using and modifying those values unless the enabled field is false. FreeCam { - sensitivity: 0.1, + sensitivity: 0.2, + friction: 25.0, walk_speed: 3.0, run_speed: 9.0, ..default() @@ -77,6 +78,83 @@ fn spawn_camera(mut commands: Commands) { )); } +// Plugin that handles camera settings controls and information text +struct CameraSettingsPlugin; +impl Plugin for CameraSettingsPlugin { + fn build(&self, app: &mut App) { + app + .add_systems(Startup, spawn_text) + .add_systems(Update, (update_camera_settings, update_text)); + } +} + +#[derive(Component)] +struct SensitivityText; + +#[derive(Component)] +struct FrictionText; + +fn spawn_text(mut commands: Commands) { + commands + .spawn(( + Text::default(), + Node { + position_type: PositionType::Absolute, + bottom: px(12), + left: px(12), + ..default() + }, + children![ + TextSpan::new("Z/X: decrease/increase sensitivity\n"), + TextSpan::new("C/V: decrease/increase friction\n"), + TextSpan::new("Current sensitivity: "), + ( + SensitivityText, + TextSpan::new("0.0"), + ), + TextSpan::new("\nCurrent friction: "), + ( + FrictionText, + TextSpan::new("0.0"), + ), + ], + )); +} + +fn update_camera_settings( + mut camera_query: Query<&mut FreeCam>, + input: Res>, +) { + let mut free_cam = camera_query.single_mut().unwrap(); + + if input.pressed(KeyCode::KeyZ) { + free_cam.sensitivity = (free_cam.sensitivity - 0.005).max(0.005); + } + if input.pressed(KeyCode::KeyX) { + free_cam.sensitivity += 0.005; + } + if input.pressed(KeyCode::KeyC) { + free_cam.friction = (free_cam.friction - 0.2).max(0.0); + } + if input.pressed(KeyCode::KeyV) { + free_cam.friction += 0.2; + } +} + +fn update_text( + mut text_sensitivity_query: Query<&mut TextSpan, (With, Without)>, + mut text_friction_query: Query<&mut TextSpan, (Without, With)>, + camera_query: Query<&FreeCam>, +) { + let mut text_sensitivity = text_sensitivity_query.single_mut().unwrap(); + let mut text_friction = text_friction_query.single_mut().unwrap(); + + let free_cam = camera_query.single().unwrap(); + + text_sensitivity.0 = format!("{:.03}", free_cam.sensitivity); + text_friction.0 = format!("{:.01}", free_cam.friction); +} + // Plugin that spawns the scene and lighting. struct ScenePlugin; impl Plugin for ScenePlugin { From 84e44322d0d4b919815121753bf7acd3e7a0c642 Mon Sep 17 00:00:00 2001 From: Pedro Yudi Honda Date: Thu, 9 Oct 2025 03:53:06 -0300 Subject: [PATCH 04/11] renames example fiel to match other code, finishes text and camera control info. --- Cargo.toml | 8 ++-- examples/README.md | 2 +- ...m_controller.rs => free_cam_controller.rs} | 48 ++++++++++--------- 3 files changed, 31 insertions(+), 27 deletions(-) rename examples/camera/{freecam_controller.rs => free_cam_controller.rs} (87%) diff --git a/Cargo.toml b/Cargo.toml index b7af76ef58734..ce1ad2631fe04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4128,14 +4128,14 @@ category = "Camera" wasm = true [[example]] -name = "freecam_controller" -path = "examples/camera/freecam_controller.rs" +name = "free_cam_controller" +path = "examples/camera/free_cam_controller.rs" doc-scrape-examples = true required-features = ["bevy_camera_controller", "free_cam"] [package.metadata.example.freecam_controller] -name = "Freecam camera controller" -description = "A freecam camera controller that showcases its basic features" +name = "Free cam camera controller" +description = "Shows the default free cam camera controller." category = "Camera" wasm = true diff --git a/examples/README.md b/examples/README.md index a41590efef426..0a758d02200f3 100644 --- a/examples/README.md +++ b/examples/README.md @@ -285,7 +285,7 @@ Example | Description [Camera Orbit](../examples/camera/camera_orbit.rs) | Shows how to orbit a static scene using pitch, yaw, and roll. [Custom Projection](../examples/camera/custom_projection.rs) | Shows how to create custom camera projections. [First person view model](../examples/camera/first_person_view_model.rs) | A first-person camera that uses a world model and a view model with different field of views (FOV) -[Freecam camera controller](../examples/camera/freecam_controller.rs) | A freecam camera controller that showcases its basic features. +[Free cam camera controller](../examples/camera/free_cam_controller.rs) | Shows the default free cam camera controller. [Projection Zoom](../examples/camera/projection_zoom.rs) | Shows how to zoom orthographic and perspective projection cameras. [Screen Shake](../examples/camera/2d_screen_shake.rs) | A simple 2D screen shake effect diff --git a/examples/camera/freecam_controller.rs b/examples/camera/free_cam_controller.rs similarity index 87% rename from examples/camera/freecam_controller.rs rename to examples/camera/free_cam_controller.rs index 27c9b802b6981..7b9916ac100a3 100644 --- a/examples/camera/freecam_controller.rs +++ b/examples/camera/free_cam_controller.rs @@ -89,15 +89,11 @@ impl Plugin for CameraSettingsPlugin { } #[derive(Component)] -struct SensitivityText; - -#[derive(Component)] -struct FrictionText; +struct InfoText; fn spawn_text(mut commands: Commands) { commands .spawn(( - Text::default(), Node { position_type: PositionType::Absolute, bottom: px(12), @@ -105,18 +101,27 @@ fn spawn_text(mut commands: Commands) { ..default() }, children![ - TextSpan::new("Z/X: decrease/increase sensitivity\n"), - TextSpan::new("C/V: decrease/increase friction\n"), - TextSpan::new("Current sensitivity: "), - ( - SensitivityText, - TextSpan::new("0.0"), - ), - TextSpan::new("\nCurrent friction: "), + Text::new(concat![ + "Z/X: decrease/increase sensitivity\n", + "C/V: decrease/increase friction", + ]), + ], + )); + + // Mutable text marked with component + commands + .spawn(( + Node { + position_type: PositionType::Absolute, + top: px(12), + left: px(12), + ..default() + }, + children![ ( - FrictionText, - TextSpan::new("0.0"), - ), + InfoText, + Text::new(""), + ) ], )); } @@ -142,17 +147,16 @@ fn update_camera_settings( } fn update_text( - mut text_sensitivity_query: Query<&mut TextSpan, (With, Without)>, - mut text_friction_query: Query<&mut TextSpan, (Without, With)>, + mut text_query: Query<&mut Text, With>, camera_query: Query<&FreeCam>, ) { - let mut text_sensitivity = text_sensitivity_query.single_mut().unwrap(); - let mut text_friction = text_friction_query.single_mut().unwrap(); + let mut text = text_query.single_mut().unwrap(); let free_cam = camera_query.single().unwrap(); - text_sensitivity.0 = format!("{:.03}", free_cam.sensitivity); - text_friction.0 = format!("{:.01}", free_cam.friction); + text.0 = format!("Sensitivity: {:.03}\nFriction: {:.01}\nSpeed: {:.02}", + free_cam.sensitivity, free_cam.friction, free_cam.velocity.length(), + ); } // Plugin that spawns the scene and lighting. From be9a82a6221e58292d29f806f3e45405856702af Mon Sep 17 00:00:00 2001 From: Pedro Yudi Honda Date: Thu, 9 Oct 2025 04:00:56 -0300 Subject: [PATCH 05/11] removes unecessary feature flag --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ce1ad2631fe04..39f602aa855c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4131,7 +4131,7 @@ wasm = true name = "free_cam_controller" path = "examples/camera/free_cam_controller.rs" doc-scrape-examples = true -required-features = ["bevy_camera_controller", "free_cam"] +required-features = ["free_cam"] [package.metadata.example.freecam_controller] name = "Free cam camera controller" From 247764761012e20f576a3242c86f90fcfae522d4 Mon Sep 17 00:00:00 2001 From: Niyudi Date: Thu, 9 Oct 2025 04:07:35 -0300 Subject: [PATCH 06/11] typos fixed --- examples/camera/free_cam_controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/camera/free_cam_controller.rs b/examples/camera/free_cam_controller.rs index 7b9916ac100a3..0ac0a9bf19bee 100644 --- a/examples/camera/free_cam_controller.rs +++ b/examples/camera/free_cam_controller.rs @@ -1,7 +1,7 @@ //! This example showcases the default freecam camera controller. //! //! The default freecam controller is useful for exploring large scenes, debugging and editing purposes. To use it, -//! simply add the [`FreeCamPlugin`] to your [`App`] and attatch the [`FreeCam`] component to the camera entity you +//! simply add the [`FreeCamPlugin`] to your [`App`] and attach the [`FreeCam`] component to the camera entity you //! wish to control. //! //! ## Default Controls @@ -66,7 +66,7 @@ fn spawn_camera(mut commands: Commands) { Camera3d::default(), Transform::from_xyz(0.0, 1.0, 0.0).looking_to(Vec3::X, Vec3::Y), // This component stores all camera settings and state, which is used by the FreeCamPlugin to - // control it. These properties can be chagned at runtime, but beware the controller system is + // control it. These properties can be changed at runtime, but beware the controller system is // constantly using and modifying those values unless the enabled field is false. FreeCam { sensitivity: 0.2, From ba64405d6fe427f53d713bfb06fbad63d89aa8c9 Mon Sep 17 00:00:00 2001 From: Pedro Yudi Honda Date: Thu, 9 Oct 2025 04:09:41 -0300 Subject: [PATCH 07/11] cargo fmt -all --- examples/camera/free_cam_controller.rs | 103 +++++++++++-------------- 1 file changed, 43 insertions(+), 60 deletions(-) diff --git a/examples/camera/free_cam_controller.rs b/examples/camera/free_cam_controller.rs index 0ac0a9bf19bee..d421274328a82 100644 --- a/examples/camera/free_cam_controller.rs +++ b/examples/camera/free_cam_controller.rs @@ -1,16 +1,16 @@ //! This example showcases the default freecam camera controller. -//! +//! //! The default freecam controller is useful for exploring large scenes, debugging and editing purposes. To use it, //! simply add the [`FreeCamPlugin`] to your [`App`] and attach the [`FreeCam`] component to the camera entity you //! wish to control. -//! +//! //! ## Default Controls -//! +//! //! This controller has a simple 6-axis control scheme, and mouse controls for camera orientation. There are also //! bindings for capturing the mouse, both while holding the button and toggle, a run feature that increases the //! max speed, and scrolling changes the movement speed. All keybinds can be changed by editing the [`FreeCam`] //! component. -//! +//! //! | Default Key Binding | Action | //! |:--------------------|:-----------------------| //! | Mouse | Look around | @@ -20,13 +20,13 @@ //! | QE | Vertical movement | //! | Left shift | Run | //! | Scroll wheel | Change movement speed | -//! +//! //! The movement speed, sensitivity and friction can also be changed by the [`FreeCam`] component. -//! +//! //! ## Example controls -//! +//! //! This example also provides a few extra keybinds to change the camera sensitivity and friction. -//! +//! //! | Key Binding | Action | //! |:------------|:---------------------| //! | Z | Decrease sensitivity | @@ -39,7 +39,7 @@ use std::f32::consts::{FRAC_PI_4, PI}; use bevy::{ camera_controller::free_cam::{FreeCam, FreeCamPlugin}, color::palettes::tailwind, - prelude::* + prelude::*, }; fn main() { @@ -56,8 +56,7 @@ fn main() { struct CameraPlugin; impl Plugin for CameraPlugin { fn build(&self, app: &mut App) { - app - .add_systems(Startup, spawn_camera); + app.add_systems(Startup, spawn_camera); } } @@ -82,8 +81,7 @@ fn spawn_camera(mut commands: Commands) { struct CameraSettingsPlugin; impl Plugin for CameraSettingsPlugin { fn build(&self, app: &mut App) { - app - .add_systems(Startup, spawn_text) + app.add_systems(Startup, spawn_text) .add_systems(Update, (update_camera_settings, update_text)); } } @@ -92,44 +90,32 @@ impl Plugin for CameraSettingsPlugin { struct InfoText; fn spawn_text(mut commands: Commands) { - commands - .spawn(( - Node { - position_type: PositionType::Absolute, - bottom: px(12), - left: px(12), - ..default() - }, - children![ - Text::new(concat![ - "Z/X: decrease/increase sensitivity\n", - "C/V: decrease/increase friction", - ]), - ], - )); - + commands.spawn(( + Node { + position_type: PositionType::Absolute, + bottom: px(12), + left: px(12), + ..default() + }, + children![Text::new(concat![ + "Z/X: decrease/increase sensitivity\n", + "C/V: decrease/increase friction", + ]),], + )); + // Mutable text marked with component - commands - .spawn(( - Node { - position_type: PositionType::Absolute, - top: px(12), - left: px(12), - ..default() - }, - children![ - ( - InfoText, - Text::new(""), - ) - ], - )); + commands.spawn(( + Node { + position_type: PositionType::Absolute, + top: px(12), + left: px(12), + ..default() + }, + children![(InfoText, Text::new(""),)], + )); } -fn update_camera_settings( - mut camera_query: Query<&mut FreeCam>, - input: Res>, -) { +fn update_camera_settings(mut camera_query: Query<&mut FreeCam>, input: Res>) { let mut free_cam = camera_query.single_mut().unwrap(); if input.pressed(KeyCode::KeyZ) { @@ -146,16 +132,16 @@ fn update_camera_settings( } } -fn update_text( - mut text_query: Query<&mut Text, With>, - camera_query: Query<&FreeCam>, -) { +fn update_text(mut text_query: Query<&mut Text, With>, camera_query: Query<&FreeCam>) { let mut text = text_query.single_mut().unwrap(); let free_cam = camera_query.single().unwrap(); - text.0 = format!("Sensitivity: {:.03}\nFriction: {:.01}\nSpeed: {:.02}", - free_cam.sensitivity, free_cam.friction, free_cam.velocity.length(), + text.0 = format!( + "Sensitivity: {:.03}\nFriction: {:.01}\nSpeed: {:.02}", + free_cam.sensitivity, + free_cam.friction, + free_cam.velocity.length(), ); } @@ -163,10 +149,7 @@ fn update_text( struct ScenePlugin; impl Plugin for ScenePlugin { fn build(&self, app: &mut App) { - app - .add_systems( - Startup, - (spawn_lights, spawn_world)); + app.add_systems(Startup, (spawn_lights, spawn_world)); } } @@ -223,7 +206,7 @@ fn spawn_world( commands.spawn(( Mesh3d(floor.clone()), MeshMaterial3d(white_material.clone()), - Transform::from_xyz(0.0, -0.01, 0.0).with_rotation(Quat::from_rotation_x(PI)) + Transform::from_xyz(0.0, -0.01, 0.0).with_rotation(Quat::from_rotation_x(PI)), )); // Blue sphere commands.spawn(( @@ -251,6 +234,6 @@ fn spawn_world( translation: Vec3::new(3.0, -2.0, 0.0), rotation: Quat::from_euler(EulerRot::YXZEx, FRAC_PI_4, FRAC_PI_4, 0.0), ..default() - } + }, )); } From 16ba085d2d527d323adfb02214f01b25db0cd01c Mon Sep 17 00:00:00 2001 From: Pedro Yudi Honda Date: Thu, 9 Oct 2025 04:14:30 -0300 Subject: [PATCH 08/11] adds forgotten _ character... --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 39f602aa855c5..4ab6d330942b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4133,7 +4133,7 @@ path = "examples/camera/free_cam_controller.rs" doc-scrape-examples = true required-features = ["free_cam"] -[package.metadata.example.freecam_controller] +[package.metadata.example.free_cam_controller] name = "Free cam camera controller" description = "Shows the default free cam camera controller." category = "Camera" From e159ac6ccb5f30879cda0ce63ee7197c1e69d852 Mon Sep 17 00:00:00 2001 From: Pedro Yudi Honda Date: Thu, 9 Oct 2025 15:02:26 -0300 Subject: [PATCH 09/11] adds more visible properties and a few keybindings for editing controlle rproperties --- examples/camera/free_cam_controller.rs | 57 ++++++++++++++++++++------ 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/examples/camera/free_cam_controller.rs b/examples/camera/free_cam_controller.rs index d421274328a82..0339250f0c9ee 100644 --- a/examples/camera/free_cam_controller.rs +++ b/examples/camera/free_cam_controller.rs @@ -25,14 +25,18 @@ //! //! ## Example controls //! -//! This example also provides a few extra keybinds to change the camera sensitivity and friction. +//! This example also provides a few extra keybinds to change the camera sensitivity, friction (how fast the camera +//! stops), scroll factor (how much scrolling changes speed) and enabling/disabling the controller. //! -//! | Key Binding | Action | -//! |:------------|:---------------------| -//! | Z | Decrease sensitivity | -//! | X | Increase snsitivity | -//! | C | Decrease friction | -//! | V | Increase friction | +//! | Key Binding | Action | +//! |:------------|:-----------------------| +//! | Z | Decrease sensitivity | +//! | X | Increase snsitivity | +//! | C | Decrease friction | +//! | V | Increase friction | +//! | F | Decrease scroll factor | +//! | G | Increase scroll factor | +//! | B | Enable/Disable | use std::f32::consts::{FRAC_PI_4, PI}; @@ -81,7 +85,7 @@ fn spawn_camera(mut commands: Commands) { struct CameraSettingsPlugin; impl Plugin for CameraSettingsPlugin { fn build(&self, app: &mut App) { - app.add_systems(Startup, spawn_text) + app.add_systems(PostStartup, spawn_text) .add_systems(Update, (update_camera_settings, update_text)); } } @@ -89,7 +93,19 @@ impl Plugin for CameraSettingsPlugin { #[derive(Component)] struct InfoText; -fn spawn_text(mut commands: Commands) { +fn spawn_text( + mut commands: Commands, + freecam_query: Query<&FreeCam>, +) { + commands.spawn(( + Node { + position_type: PositionType::Absolute, + top: px(-16), + left: px(12), + ..default() + }, + children![Text::new(format!("{}", freecam_query.single().unwrap()))], + )); commands.spawn(( Node { position_type: PositionType::Absolute, @@ -99,7 +115,9 @@ fn spawn_text(mut commands: Commands) { }, children![Text::new(concat![ "Z/X: decrease/increase sensitivity\n", - "C/V: decrease/increase friction", + "C/V: decrease/increase friction\n", + "F/G: decrease/increase scroll factor\n", + "B: enable/disable controller", ]),], )); @@ -108,10 +126,10 @@ fn spawn_text(mut commands: Commands) { Node { position_type: PositionType::Absolute, top: px(12), - left: px(12), + right: px(12), ..default() }, - children![(InfoText, Text::new(""),)], + children![(InfoText, Text::new(""))], )); } @@ -130,6 +148,15 @@ fn update_camera_settings(mut camera_query: Query<&mut FreeCam>, input: Res>, camera_query: Query<&FreeCam>) { @@ -138,9 +165,13 @@ fn update_text(mut text_query: Query<&mut Text, With>, camera_query: Q let free_cam = camera_query.single().unwrap(); text.0 = format!( - "Sensitivity: {:.03}\nFriction: {:.01}\nSpeed: {:.02}", + "Enabled: {},\nSensitivity: {:.03}\nFriction: {:.01}\nScroll factor: {:.02}\nWalk Speed: {:.02}\nRun Speed: {:.02}\nSpeed: {:.02}", + free_cam.enabled, free_cam.sensitivity, free_cam.friction, + free_cam.scroll_factor, + free_cam.walk_speed, + free_cam.run_speed, free_cam.velocity.length(), ); } From 491937cdbdbb21ba180efa01de87eed4ec5f64ba Mon Sep 17 00:00:00 2001 From: Pedro Yudi Honda Date: Thu, 9 Oct 2025 15:12:18 -0300 Subject: [PATCH 10/11] cargo fmt --all --- examples/camera/free_cam_controller.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/camera/free_cam_controller.rs b/examples/camera/free_cam_controller.rs index 0339250f0c9ee..32108971e1e83 100644 --- a/examples/camera/free_cam_controller.rs +++ b/examples/camera/free_cam_controller.rs @@ -93,10 +93,7 @@ impl Plugin for CameraSettingsPlugin { #[derive(Component)] struct InfoText; -fn spawn_text( - mut commands: Commands, - freecam_query: Query<&FreeCam>, -) { +fn spawn_text(mut commands: Commands, freecam_query: Query<&FreeCam>) { commands.spawn(( Node { position_type: PositionType::Absolute, From e2c9d11618875060e5c852b38595dd488aec2e7f Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Thu, 9 Oct 2025 15:11:36 -0400 Subject: [PATCH 11/11] Fix typo --- examples/camera/free_cam_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/camera/free_cam_controller.rs b/examples/camera/free_cam_controller.rs index 32108971e1e83..1443dda8519f3 100644 --- a/examples/camera/free_cam_controller.rs +++ b/examples/camera/free_cam_controller.rs @@ -31,7 +31,7 @@ //! | Key Binding | Action | //! |:------------|:-----------------------| //! | Z | Decrease sensitivity | -//! | X | Increase snsitivity | +//! | X | Increase sensitivity | //! | C | Decrease friction | //! | V | Increase friction | //! | F | Decrease scroll factor |