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." <mat.stjr@gmail.com>
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<MovementSettings>,
scroll_type: Res<State<ScrollType>>,
- mut mouse_wheel_events: EventReader<MouseWheel>,
+ mut mouse_wheel_events: MessageReader<MouseWheel>,
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." <mat.stjr@gmail.com>
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 <sburris@posteo.net>"]
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." <mat.stjr@gmail.com>
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::<MovementSettings>()
- .init_resource::<KeyBindings>()
- .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::<MovementSettings>()
- .init_resource::<KeyBindings>()
- .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::<MovementSettings>()
+ .init_resource::<KeyBindings>()
+ .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 <sburris@posteo.net>"]
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
[](https://crates.io/crates/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. </br>
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
[](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<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 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<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 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::<ScrollType>()
.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<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 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<State<ScrollType>>,
mut next_scroll_type: ResMut<NextState<ScrollType>>,
keyboard_input: Res<ButtonInput<KeyCode>>,
) {
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<MovementSettings>,
scroll_type: Res<State<ScrollType>>,
mut mouse_wheel_events: MessageReader<MouseWheel>,
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 <nixpkgs> { } }:
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<PrimaryWindow>>) {
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<PrimaryWindow>>) {
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<ButtonInput<KeyCode>>,
time: Res<Time>,
primary_cursor_options: Single<&mut CursorOptions, With<PrimaryWindow>>,
settings: Res<MovementSettings>,
key_bindings: Res<KeyBindings>,
mut query: Query<(&FlyCam, &mut Transform)>, // mut query: Query<&mut Transform, With<FlyCam>>,
) {
for (_camera, mut transform) in query.iter_mut() {
let mut velocity = Vec3::ZERO;
let local_z = transform.local_z();
let forward = -Vec3::new(local_z.x, 0., local_z.z);
let right = Vec3::new(local_z.z, 0., -local_z.x);
for key in keys.get_pressed() {
match primary_cursor_options.grab_mode {
CursorGrabMode::None => (),
_ => {
let key = *key;
if key == key_bindings.move_forward {
velocity += forward;
} else if key == key_bindings.move_backward {
velocity -= forward;
} else if key == key_bindings.move_left {
velocity -= right;
} else if key == key_bindings.move_right {
velocity += right;
} else if key == key_bindings.move_ascend {
velocity += Vec3::Y;
} else if key == key_bindings.move_descend {
velocity -= Vec3::Y;
}
}
}
}
velocity = velocity.normalize_or_zero();
transform.translation += velocity * time.delta_secs() * settings.speed
}
}
/// Handles looking around if cursor is locked
fn player_look(
settings: Res<MovementSettings>,
primary_window: Query<&mut Window, With<PrimaryWindow>>,
primary_cursor_options: Single<&mut CursorOptions, With<PrimaryWindow>>,
mut state: MessageReader<MouseMotion>,
mut query: Query<&mut Transform, With<FlyCam>>,
) {
if let Ok(window) = primary_window.single() {
for mut transform in query.iter_mut() {
for ev in state.read() {
let (mut yaw, mut pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
match primary_cursor_options.grab_mode {
CursorGrabMode::None => (),
_ => {
// Using smallest of height or width ensures equal vertical and horizontal sensitivity
let window_scale = window.height().min(window.width());
pitch -= (settings.sensitivity * ev.delta.y * window_scale).to_radians();
yaw -= (settings.sensitivity * ev.delta.x * window_scale).to_radians();
}
}
pitch = pitch.clamp(-1.54, 1.54);
// Order is important to prevent unintended roll
transform.rotation =
Quat::from_axis_angle(Vec3::Y, yaw) * Quat::from_axis_angle(Vec3::X, pitch);
}
}
} else {
warn!("Primary window not found for `player_look`!");
}
}
fn cursor_grab(
keys: Res<ButtonInput<KeyCode>>,
key_bindings: Res<KeyBindings>,
primary_cursor_options: Single<&mut CursorOptions, With<PrimaryWindow>>,
) {
if keys.just_pressed(key_bindings.toggle_grab_cursor) {
toggle_grab_cursor(primary_cursor_options);
}
}
// Grab cursor when an entity with FlyCam is added
fn initial_grab_on_flycam_spawn(
query_added: Query<Entity, Added<FlyCam>>,
primary_cursor_options: Single<&mut CursorOptions, With<PrimaryWindow>>,
) {
if query_added.is_empty() {
return;
}
toggle_grab_cursor(primary_cursor_options);
}
/// Contains everything needed to add first-person fly camera behavior to your game
pub struct PlayerPlugin;
impl Plugin for PlayerPlugin {
fn build(&self, app: &mut App) {
common_build(app);
app.add_systems(Startup, setup_player);
}
}
/// Same as [`PlayerPlugin`] but does not spawn a camera
pub struct NoCameraPlayerPlugin;
impl Plugin for NoCameraPlayerPlugin {
fn build(&self, app: &mut App) {
common_build(app);
}
}
/// Common build steps for both PlayerPlugin and NoCameraPlayerPlugin
fn common_build(app: &mut App) {
app.init_resource::<MovementSettings>()
.init_resource::<KeyBindings>()
.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);
}
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
SYMBOL INDEX (26 symbols across 4 files)
FILE: examples/basic.rs
function main (line 7) | fn main() {
function setup (line 20) | fn setup(
FILE: examples/key_bindings.rs
function main (line 7) | fn main() {
function setup (line 26) | fn setup(
FILE: examples/scroll.rs
type ScrollType (line 8) | enum ScrollType {
function main (line 14) | fn main() {
function setup (line 31) | fn setup(
function switch_scroll_type (line 65) | fn switch_scroll_type(
function scroll (line 82) | fn scroll(
FILE: src/lib.rs
type MovementSettings (line 11) | pub struct MovementSettings {
method default (line 17) | fn default() -> Self {
type KeyBindings (line 27) | pub struct KeyBindings {
method default (line 38) | fn default() -> Self {
type FlyCam (line 54) | pub struct FlyCam;
function toggle_grab_cursor (line 57) | fn toggle_grab_cursor(mut primary_cursor_options: Single<&mut CursorOpti...
function initial_grab_cursor (line 71) | fn initial_grab_cursor(primary_cursor_options: Single<&mut CursorOptions...
function setup_player (line 76) | fn setup_player(mut commands: Commands) {
function player_move (line 85) | fn player_move(
function player_look (line 128) | fn player_look(
function cursor_grab (line 161) | fn cursor_grab(
function initial_grab_on_flycam_spawn (line 172) | fn initial_grab_on_flycam_spawn(
type PlayerPlugin (line 184) | pub struct PlayerPlugin;
method build (line 186) | fn build(&self, app: &mut App) {
type NoCameraPlayerPlugin (line 193) | pub struct NoCameraPlayerPlugin;
method build (line 195) | fn build(&self, app: &mut App) {
function common_build (line 201) | fn common_build(app: &mut App) {
Condensed preview — 11 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (26K chars).
[
{
"path": ".github/workflows/rust.yml",
"chars": 1358,
"preview": "on: [push, pull_request]\n\nname: Continuous integration\n\njobs:\n update:\n name: Update\n runs-on: ubuntu-latest\n "
},
{
"path": ".gitignore",
"chars": 334,
"preview": "# Generated by Cargo\n# will have compiled files and executables\n/target/\n\n# Remove Cargo.lock from gitignore if creating"
},
{
"path": "61.patch",
"chars": 4506,
"preview": "From a29e882381d84b3a7aa0247ab5e0aad9ff0515da Mon Sep 17 00:00:00 2001\nFrom: \"Mathys R.\" <mat.stjr@gmail.com>\nDate: Wed,"
},
{
"path": "Cargo.toml",
"chars": 990,
"preview": "[package]\nname = \"bevy_flycam\"\nversion = \"0.18.0\"\nauthors = [\"Spencer Burris <sburris@posteo.net>\"]\nedition = \"2021\"\nlic"
},
{
"path": "LICENSE.md",
"chars": 728,
"preview": "Copyright 2020 Spencer Burris\n\nPermission to use, copy, modify, and/or distribute this software for any purpose with or "
},
{
"path": "README.md",
"chars": 3380,
"preview": "# bevy_flycam\n\n[](https://crates.io/crates/bevy_flycam)\n![Crate"
},
{
"path": "examples/basic.rs",
"chars": 1342,
"preview": "use bevy::prelude::*;\nuse bevy_flycam::prelude::*;\n\n//From bevy examples:\n//https://github.com/bevyengine/bevy/blob/late"
},
{
"path": "examples/key_bindings.rs",
"chars": 1307,
"preview": "use bevy::prelude::*;\nuse bevy_flycam::prelude::*;\n\n//From bevy examples:\n//https://github.com/bevyengine/bevy/blob/late"
},
{
"path": "examples/scroll.rs",
"chars": 3210,
"preview": "use bevy::{input::mouse::MouseWheel, prelude::*};\nuse bevy_flycam::prelude::*;\n\n// From bevy examples:\n// https://github"
},
{
"path": "shell.nix",
"chars": 351,
"preview": "{ pkgs ? import <nixpkgs> { } }:\n\nwith pkgs;\n\nmkShell rec {\n nativeBuildInputs = [\n pkg-config\n ];\n buildInputs = "
},
{
"path": "src/lib.rs",
"chars": 6913,
"preview": "use bevy::input::mouse::MouseMotion;\nuse bevy::prelude::*;\nuse bevy::window::{CursorGrabMode, CursorOptions, PrimaryWind"
}
]
About this extraction
This page contains the full source code of the sburris0/bevy_flycam GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 11 files (23.8 KB), approximately 6.9k tokens, and a symbol index with 26 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.