Repository: sburris0/bevy_flycam Branch: master Commit: 72a51236575f Files: 11 Total size: 23.8 KB Directory structure: gitextract_2grpx0la/ ├── .github/ │ └── workflows/ │ └── rust.yml ├── .gitignore ├── 61.patch ├── Cargo.toml ├── LICENSE.md ├── README.md ├── examples/ │ ├── basic.rs │ ├── key_bindings.rs │ └── scroll.rs ├── shell.nix └── src/ └── lib.rs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/rust.yml ================================================ on: [push, pull_request] name: Continuous integration jobs: update: name: Update runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - run: cargo update check: name: Check runs-on: ubuntu-latest needs: update steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - run: cargo check test: name: Test Suite runs-on: ubuntu-latest needs: update steps: - uses: actions/checkout@v3 - name: Update apt run: sudo apt update - name: Install libudev run: sudo apt install libudev-dev - name: Install libxkbcommon run: sudo apt install libxkbcommon-dev - name: Install libwayland run: sudo apt install libwayland-dev - uses: dtolnay/rust-toolchain@stable - run: cargo test fmt: name: Rustfmt runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - run: rustup component add rustfmt - run: cargo fmt --all -- --check clippy: name: Clippy runs-on: ubuntu-latest needs: update steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - run: rustup component add clippy - run: cargo clippy -- -D warnings ================================================ FILE: .gitignore ================================================ # Generated by Cargo # will have compiled files and executables /target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk # IDE .idea/ ================================================ FILE: 61.patch ================================================ From a29e882381d84b3a7aa0247ab5e0aad9ff0515da Mon Sep 17 00:00:00 2001 From: "Mathys R." Date: Wed, 14 Jan 2026 17:29:26 -0500 Subject: [PATCH 1/3] fix(deprecated): replaced deprecated EventReader to MessageReader --- examples/scroll.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/scroll.rs b/examples/scroll.rs index 95830a1..8b0049f 100644 --- a/examples/scroll.rs +++ b/examples/scroll.rs @@ -82,7 +82,7 @@ fn switch_scroll_type( fn scroll( mut settings: ResMut, scroll_type: Res>, - mut mouse_wheel_events: EventReader, + mut mouse_wheel_events: MessageReader, mut query: Query<(&FlyCam, &mut Projection)>, ) { for event in mouse_wheel_events.read() { From 70f2e7e1cb08ad6a25c03f0e80af0ea89a262b86 Mon Sep 17 00:00:00 2001 From: "Mathys R." Date: Wed, 14 Jan 2026 17:29:46 -0500 Subject: [PATCH 2/3] chore(version): bump version to 0.18.0 --- Cargo.toml | 6 +++--- README.md | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 93db9a0..041041c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_flycam" -version = "0.17.0" +version = "0.18.0" authors = ["Spencer Burris "] edition = "2021" license = "ISC" @@ -13,7 +13,7 @@ categories = ["game-engines", "game-development"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bevy = { version = "0.17", default-features = false, features = [ +bevy = { version = "0.18", default-features = false, features = [ "std", "bevy_asset", "bevy_core_pipeline", @@ -23,7 +23,7 @@ bevy = { version = "0.17", default-features = false, features = [ ] } [dev-dependencies] -bevy = { version = "0.17", default-features = false, features = [ +bevy = { version = "0.18", default-features = false, features = [ "bevy_asset", "bevy_core_pipeline", "bevy_pbr", diff --git a/README.md b/README.md index 9896e7a..2e00f2f 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ fn setup(mut commands: Commands) { bevy_flycam's crate version follows bevy's minor version as shown: | bevy | bevy_flycam | | :-- | :-- | +| `0.18.0` | `0.18.0` | | `0.17.2` | `0.17.2` | | `0.16.1` | `0.16.1` | | `0.15.0` | `0.15.0` | From 29c24d2d115d0720e5840b1033947f55ae2f7fb4 Mon Sep 17 00:00:00 2001 From: "Mathys R." Date: Wed, 14 Jan 2026 17:30:16 -0500 Subject: [PATCH 3/3] refactor: creating a common_build function to avoid duplicate code. --- src/lib.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ce44401..700e358 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -184,13 +184,8 @@ fn initial_grab_on_flycam_spawn( pub struct PlayerPlugin; impl Plugin for PlayerPlugin { fn build(&self, app: &mut App) { - app.init_resource::() - .init_resource::() - .add_systems(Startup, setup_player) - .add_systems(Startup, initial_grab_cursor) - .add_systems(Update, player_move) - .add_systems(Update, player_look) - .add_systems(Update, cursor_grab); + common_build(app); + app.add_systems(Startup, setup_player); } } @@ -198,12 +193,17 @@ impl Plugin for PlayerPlugin { pub struct NoCameraPlayerPlugin; impl Plugin for NoCameraPlayerPlugin { fn build(&self, app: &mut App) { - app.init_resource::() - .init_resource::() - .add_systems(Startup, initial_grab_cursor) - .add_systems(Startup, initial_grab_on_flycam_spawn) - .add_systems(Update, player_move) - .add_systems(Update, player_look) - .add_systems(Update, cursor_grab); + common_build(app); } } + +/// Common build steps for both PlayerPlugin and NoCameraPlayerPlugin +fn common_build(app: &mut App) { + app.init_resource::() + .init_resource::() + .add_systems(Startup, initial_grab_cursor) + .add_systems(Startup, initial_grab_on_flycam_spawn) + .add_systems(Update, player_move) + .add_systems(Update, player_look) + .add_systems(Update, cursor_grab); +} \ No newline at end of file ================================================ FILE: Cargo.toml ================================================ [package] name = "bevy_flycam" version = "0.18.0" authors = ["Spencer Burris "] edition = "2021" license = "ISC" description = "Basic first-person fly camera for the Bevy game engine" homepage = "https://github.com/sburris0/bevy_flycam/" repository = "https://github.com/sburris0/bevy_flycam/" readme = "README.md" keywords = ["gamedev", "bevy", "3d", "camera"] categories = ["game-engines", "game-development"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] bevy = { version = "0.18", default-features = false, features = [ "std", "bevy_asset", "bevy_core_pipeline", "bevy_render", "bevy_log", "bevy_window", ] } [dev-dependencies] bevy = { version = "0.18", default-features = false, features = [ "bevy_asset", "bevy_core_pipeline", "bevy_pbr", "bevy_state", "bevy_window", "ktx2", "tonemapping_luts", "wayland", "x11", "zstd_rust", ] } ================================================ FILE: LICENSE.md ================================================ Copyright 2020 Spencer Burris Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: README.md ================================================ # bevy_flycam [![Crates.io](https://img.shields.io/crates/v/bevy_flycam)](https://crates.io/crates/bevy_flycam) ![Crates.io](https://img.shields.io/crates/l/bevy_flycam) ![docs.rs](https://img.shields.io/docsrs/bevy_flycam) A basic first-person fly camera for Bevy ## Controls - WASD to move horizontally - SPACE to ascend - LSHIFT to descend - ESC to grab/release cursor. ## Comparison There are a few notable differences from [bevy_fly_camera](https://github.com/mcpar-land/bevy_fly_camera)... - No linear interpolation - Cursor grabbing - Shorter code - Single-line setup - A tiny bit faster? ## Usage 1. Add to `Cargo.toml` or copy `lib.rs` to your own file ```toml [dependencies] bevy = "0.18" bevy_flycam = "*" ``` or ```toml [dependencies] bevy = "0.18" bevy_flycam = { git = "https://github.com/sburris0/bevy_flycam" } ``` 2. Include the prelude: ```rust use bevy_flycam::prelude::*; ``` 3. Add the `PlayerPlugin`: ```rust #[bevy_main] fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(PlayerPlugin) .run(); } ``` Note that `PlayerPlugin` will spawn a camera for you. See [Using your own camera](#using-your-own-camera) for details on how to use a pre-existing one. Alternatively you can see the example `basic.rs` or `scroll.rs` located in the examples folder. You can run the example by cloning this repository and run the command: `cargo run --release --example basic` ## Customization ### Movement and keybindings To modify player movement speed or mouse sensitivity add it as a resource.
Same thing goes for the keybindings used for moving the camera. ```Rust #[bevy_main] fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(PlayerPlugin) .insert_resource(MovementSettings { sensitivity: 0.00015, // default: 0.00012 speed: 12.0, // default: 12.0 }) .insert_resource(KeyBindings { move_ascend: KeyCode::E, move_descend: KeyCode::Q, ..Default::default() }) .run(); } ``` ### Using your own camera You can also use `NoCameraPlayerPlugin` if you want to use your own camera. Be sure to add the `FlyCam` component to your own camera or else this plugin won't know what to move. ```Rust #[bevy_main] fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(NoCameraPlayerPlugin) .add_systems(Startup, setup) .run(); } fn setup(mut commands: Commands) { commands.spawn(( Camera3dBundle { transform: Transform::from_xyz(0.0, 2.0, 0.5), ..default() }, FlyCam )); } ``` ## Support [![Bevy tracking](https://img.shields.io/badge/Bevy%20tracking-released%20version-lightblue)](https://github.com/bevyengine/bevy/blob/main/docs/plugins_guidelines.md#main-branch-tracking) bevy_flycam's crate version follows bevy's minor version as shown: | bevy | bevy_flycam | | :-- | :-- | | `0.18.0` | `0.18.0` | | `0.17.2` | `0.17.2` | | `0.16.1` | `0.16.1` | | `0.15.0` | `0.15.0` | | `0.14.0` | `0.14.0` | | `0.13.0` | `0.13.0` | | `0.12.0` | `0.12.0` | | `0.11.0` | `0.11.0` | | `0.10.1` | `0.10.1` | ## Contributing PRs are very welcome. ================================================ FILE: examples/basic.rs ================================================ use bevy::prelude::*; use bevy_flycam::prelude::*; //From bevy examples: //https://github.com/bevyengine/bevy/blob/latest/examples/3d/3d_scene.rs fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(PlayerPlugin) .insert_resource(MovementSettings { sensitivity: 0.00015, // default: 0.00012 speed: 12.0, // default: 12.0 }) .add_systems(Startup, setup) .run(); } /// set up a simple 3D scene fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, ) { // plane commands.spawn(( Mesh3d(meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(2.5)))), MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))), )); // cube commands.spawn(( Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))), MeshMaterial3d(materials.add(Color::srgb(0.8, 0.7, 0.6))), Transform::from_xyz(0.0, 0.5, 0.0), )); // light commands.spawn((PointLight::default(), Transform::from_xyz(4.0, 8.0, 4.0))); info!("Move camera around by using WASD for lateral movement"); info!("Use Left Shift and Spacebar for vertical movement"); info!("Use the mouse to look around"); info!("Press Esc to hide or show the mouse cursor"); } ================================================ FILE: examples/key_bindings.rs ================================================ use bevy::prelude::*; use bevy_flycam::prelude::*; //From bevy examples: //https://github.com/bevyengine/bevy/blob/latest/examples/3d/3d_scene.rs fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(PlayerPlugin) .insert_resource(MovementSettings { sensitivity: 0.00015, // default: 0.00012 speed: 12.0, // default: 12.0 }) // Unreal movement layout .insert_resource(KeyBindings { move_ascend: KeyCode::KeyE, move_descend: KeyCode::KeyQ, ..Default::default() }) .add_systems(Startup, setup) .run(); } /// set up a simple 3D scene fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, ) { // plane commands.spawn(( Mesh3d(meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(2.5)))), MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))), )); // cube commands.spawn(( Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))), MeshMaterial3d(materials.add(Color::srgb(0.8, 0.7, 0.6))), Transform::from_xyz(0.0, 0.5, 0.0), )); // light commands.spawn((PointLight::default(), Transform::from_xyz(4.0, 8.0, 4.0))); } ================================================ FILE: examples/scroll.rs ================================================ use bevy::{input::mouse::MouseWheel, prelude::*}; use bevy_flycam::prelude::*; // From bevy examples: // https://github.com/bevyengine/bevy/blob/latest/examples/3d/3d_scene.rs #[derive(States, Default, Clone, Eq, PartialEq, Debug, Hash)] enum ScrollType { #[default] MovementSpeed, Zoom, } fn main() { App::new() .add_plugins(DefaultPlugins) //NoCameraPlayerPlugin as we provide the camera .add_plugins(NoCameraPlayerPlugin) .insert_resource(MovementSettings { ..Default::default() }) // Setting initial state .init_state::() .add_systems(Startup, setup) .add_systems(Update, switch_scroll_type) .add_systems(Update, scroll) .run(); } /// set up a simple 3D scene fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, ) { // plane commands.spawn(( Mesh3d(meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(2.5)))), MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))), )); // cube commands.spawn(( Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))), MeshMaterial3d(materials.add(Color::srgb(0.8, 0.7, 0.6))), Transform::from_xyz(0.0, 0.5, 0.0), )); // light // light commands.spawn((PointLight::default(), Transform::from_xyz(4.0, 8.0, 4.0))); // add camera commands.spawn(( Camera3d::default(), Transform::from_xyz(-2.0, 5.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y), FlyCam, )); info!("Press 'Z' to switch between Movement Speed and Zoom"); info!("Changing the selected value by scrolling the mousewheel"); } /// Listens for Z key being pressed and toggles between the two scroll-type states [`ScrollType`] fn switch_scroll_type( scroll_type: Res>, mut next_scroll_type: ResMut>, keyboard_input: Res>, ) { if keyboard_input.just_pressed(KeyCode::KeyZ) { let result = match scroll_type.get() { ScrollType::MovementSpeed => ScrollType::Zoom, ScrollType::Zoom => ScrollType::MovementSpeed, }; println!("{:?}", result); next_scroll_type.set(result); } } /// Depending on the state, the mouse-scroll changes either the movement speed or the field-of-view of the camera fn scroll( mut settings: ResMut, scroll_type: Res>, mut mouse_wheel_events: MessageReader, mut query: Query<(&FlyCam, &mut Projection)>, ) { for event in mouse_wheel_events.read() { if *scroll_type.get() == ScrollType::MovementSpeed { settings.speed = (settings.speed + event.y * 0.1).abs(); println!("Speed: {:?}", settings.speed); } else { for (_camera, project) in query.iter_mut() { if let Projection::Perspective(perspective) = project.into_inner() { perspective.fov = (perspective.fov - event.y * 0.01).abs(); println!("FOV: {:?}", perspective.fov); } } } } } ================================================ FILE: shell.nix ================================================ { pkgs ? import { } }: with pkgs; mkShell rec { nativeBuildInputs = [ pkg-config ]; buildInputs = [ udev alsa-lib vulkan-loader xorg.libX11 xorg.libXcursor xorg.libXi xorg.libXrandr # To use the x11 feature libxkbcommon wayland # To use the wayland feature ]; LD_LIBRARY_PATH = lib.makeLibraryPath buildInputs; } ================================================ FILE: src/lib.rs ================================================ use bevy::input::mouse::MouseMotion; use bevy::prelude::*; use bevy::window::{CursorGrabMode, CursorOptions, PrimaryWindow}; pub mod prelude { pub use crate::*; } /// Mouse sensitivity and movement speed #[derive(Resource)] pub struct MovementSettings { pub sensitivity: f32, pub speed: f32, } impl Default for MovementSettings { fn default() -> Self { Self { sensitivity: 0.00012, speed: 12., } } } /// Key configuration #[derive(Resource)] pub struct KeyBindings { pub move_forward: KeyCode, pub move_backward: KeyCode, pub move_left: KeyCode, pub move_right: KeyCode, pub move_ascend: KeyCode, pub move_descend: KeyCode, pub toggle_grab_cursor: KeyCode, } impl Default for KeyBindings { fn default() -> Self { Self { move_forward: KeyCode::KeyW, move_backward: KeyCode::KeyS, move_left: KeyCode::KeyA, move_right: KeyCode::KeyD, move_ascend: KeyCode::Space, move_descend: KeyCode::ShiftLeft, toggle_grab_cursor: KeyCode::Escape, } } } /// Used in queries when you want flycams and not other cameras /// A marker component used in queries when you want flycams and not other cameras #[derive(Component)] pub struct FlyCam; /// Grabs/ungrabs mouse cursor fn toggle_grab_cursor(mut primary_cursor_options: Single<&mut CursorOptions, With>) { match primary_cursor_options.grab_mode { CursorGrabMode::None => { primary_cursor_options.grab_mode = CursorGrabMode::Confined; primary_cursor_options.visible = false; } _ => { primary_cursor_options.grab_mode = CursorGrabMode::None; primary_cursor_options.visible = true; } } } /// Grabs the cursor when game first starts fn initial_grab_cursor(primary_cursor_options: Single<&mut CursorOptions, With>) { toggle_grab_cursor(primary_cursor_options); } /// Spawns the `Camera3dBundle` to be controlled fn setup_player(mut commands: Commands) { commands.spawn(( Camera3d::default(), FlyCam, Transform::from_xyz(-2.0, 5.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y), )); } /// Handles keyboard input and movement fn player_move( keys: Res>, time: Res