Basic first-person fly camera for the Bevy game engine

Overview

bevy_flycam

Crates.io Crates.io docs.rs

A basic first-person fly camera for Bevy 0.4

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...

  • 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
[dependencies]
bevy = "0.4"
bevy_flycam = "*"

or

[dependencies]
bevy = "0.4"
bevy_flycam = { git = "https://github.com/sburris0/bevy_flycam" }
  1. Include the PlayerPlugin
use bevy_flycam::PlayerPlugin;

This will spawn a camera for you. Use NoCameraPlayerPlugin if you do not want this and make sure to use .with(FlyCam) on your own camera or else this plugin won't know what to move.

  1. Add the PlayerPlugin:
#[bevy_main]
fn main() {
    App::build()
        .add_plugins(DefaultPlugins)
        .add_plugin(PlayerPlugin)
        .run();
}

Customization

To modify player movement speed or mouse sensitivity, import bevy_flycam::MovementSettings and add it as a resource:

#[bevy_main]
fn main() {
    App::build()
        .add_plugins(DefaultPlugins)
        .add_plugin(PlayerPlugin)
        .add_resource(MovementSettings {
            sensitivity: 0.00015, // default: 0.00012
            speed: 150.0, // default: 12.0
        })
        .run();
}

Contributing

PRs are very welcome.

Comments
  • Migrate to `bevy` v0.6

    Migrate to `bevy` v0.6

    This PR mostly deals with breaking changes from migrating to bevy version 0.6, as per the Bevy migration guide.

    Some callouts:

    • Used StorageType::SparseSet for FlyCam, since I expect it to only exist approximately for one entity.
    • Added [[example]] sections to the repository config.
    opened by mnett82 8
  • Inconsistent sensitivity between pitch and yaw

    Inconsistent sensitivity between pitch and yaw

    Looking up and down (pitch) is a bit slower than left and right (yaw), which feels weird in my experience. It a lot slower the more wide the window (maybe too slow if fullscreen on a 21:9).

    I think this is caused by multiplying the sensitivity and delta by the window.height() or * window.width(). After removing this multiplication, I get a consistent sensitivity in all directions. May I ask why this is being done?

    opened by TarekAS 4
  • Removed window `unwrap()`s

    Removed window `unwrap()`s

    Fixes #19

    What is the problem?

    When closing a Bevy app, the window may be closed but the application is still running. Some bevy_flycam systems try to access the window, and in the process unwrap an Option<&mut Window>. If that Option is None, the application crashes.

    What is the solution?

    This PR changes those unwrap()s to matching patterns. Now, when a window isn't found, a warning is given instead.

    What is the alternative?

    This is still proper error handling, but gives unnecessary warnings when closing. There may be a way to use run criteria to stop the systems when AppExit events are sent, but I was unable to get this to work (presumably because of event delays). ~~It would probably be better if Bevy provided an AppState resource from which the global state of the application could be checked and then use that for a run criteria.~~ (Now that I think about it, explicit system ordering may be the solution)

    opened by JonahPlusPlus 3
  • Discussion: Would the addition of a KeyMap create value for users?

    Discussion: Would the addition of a KeyMap create value for users?

    Something like this (I've already got it to work locally): Its using 'static lifetime elision, so that we don't need to store anything in the heap. Changes to lib.rs:

    pub struct KeyMap { 
        pub forward: &'static[KeyCode],
        pub backward: &'static[KeyCode],
        pub left: &'static[KeyCode],
        pub right: &'static[KeyCode],
        pub up: &'static[KeyCode],
        pub down: &'static[KeyCode],
    }
    
    impl Default for KeyMap {
        fn default() -> Self {
            Self {
                forward: &[KeyCode::W],
                backward: &[KeyCode::S],
                left: &[KeyCode::A],
                right: &[KeyCode::D],
                up: &[KeyCode::Space],
                down: &[KeyCode::LShift],
            }
        }
    }
    
    /// Mouse sensitivity and movement speed
    pub struct MovementSettings {
        pub sensitivity: f32,
        pub speed: f32,
        pub map: KeyMap,
    }
    
    impl Default for MovementSettings {
        fn default() -> Self {
            Self {
                sensitivity: 0.00012,
                speed: 12.,
                map: KeyMap::default()
            }
        }
    }
    
    fn validate_key(codes:&'static[KeyCode], key: &KeyCode) -> bool {
        codes.iter().any(|m| m == key)
    }
    
    fn player_move(
        keys: Res<Input<KeyCode>>,
        time: Res<Time>,
        windows: Res<Windows>,
        settings: Res<MovementSettings>,
        mut query: Query<(&FlyCam, &mut Transform)>,
    ) {
        let window = windows.get_primary().unwrap();
        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() {
                if window.cursor_locked() {
    				//----- Changes here ------\\
                    if validate_key(settings.map.forward,  key) {velocity += forward }
                    if validate_key(settings.map.backward, key) {velocity -= forward }
                    if validate_key(settings.map.left,     key) {velocity -= right   }
                    if validate_key(settings.map.right,    key) {velocity += right   }
                    if validate_key(settings.map.up,       key) {velocity += unit_y()}
                    if validate_key(settings.map.down,     key) {velocity -= unit_y()}            
                }
            }
    
            velocity = velocity.normalize();
    
            if !velocity.is_nan() {
                transform.translation += velocity * time.delta_seconds() * settings.speed
            }
        }
    }
    

    Usage (or using default)

    .insert_resource(MovementSettings {
        sensitivity: 0.00015, // default: 0.00012
        speed: 12.0, // default: 12.0
        map: KeyMap {
            forward: &[KeyCode::Up, KeyCode::W],
            ..Default::default()
        }
    })
    

    The question is: Does it add unnecessary complexity that takes away the simplicity of the library for the benefit of the user? On one hand, it's an opt-in feature and not a breaking feature if you are only using defaults. On the other hand, you still have breaking changes for any have something custom using the lib.

    opened by BlackPhlox 2
  • Camera queries can be simplified

    Camera queries can be simplified

    Following queries can be simplified using With filter, since FlyCam is just a marker component.

    https://github.com/sburris0/bevy_flycam/blob/100a15d412b2419e463dc73fd0de50ef4b31b97b/src/lib.rs#L59-L62

    https://github.com/sburris0/bevy_flycam/blob/100a15d412b2419e463dc73fd0de50ef4b31b97b/src/lib.rs#L94-L97

         mut query: Query<&mut Transform, With<FlyCam>>,
     ) { 
         let window = windows.get_primary().unwrap(); 
         for mut transform in query.iter_mut() { 
    
    opened by tguichaoua 1
  • Fixed zoom and cleaned switch_scroll_type in scroll.rs example

    Fixed zoom and cleaned switch_scroll_type in scroll.rs example

    Hello again 👋

    Figured out how bevy's camera and its camera projection works. So now I was able to implement the zoom functionality correctly so that it works now, yay. 🎉

    opened by BlackPhlox 1
  • New scroll example and reduced compile time for lib using dev-dependencies

    New scroll example and reduced compile time for lib using dev-dependencies

    Don't merge quite yet, I want to hear your opinion. Also, for some reason changing the FOV (the scroll.rs) of the camera doesn't work even though it does change, maybe the fov is only read on initialization?

    opened by BlackPhlox 1
  • typo fix

    typo fix

    Thank you for your work on this crate! I found a typo while trying out the example provided in the README.md. let me know if you have any feedback or additional thoughts.

    opened by DJames239 1
  • Panics when window closes

    Panics when window closes

    Working on the Bevy 0.8 release of bevy_atmosphere (link to current commit tree). I noticed that when I run my example (cargo run --example cycle --feature dynamic) and close the window, it actually crashes. I get the following error log:

    2022-08-03T00:13:27.505579Z  INFO bevy_winit: Skipped event for closed window: WindowId(00000000-0000-0000-0000-000000000000)
    2022-08-03T00:13:27.506219Z  INFO bevy_winit: Skipped event for closed window: WindowId(00000000-0000-0000-0000-000000000000)
    2022-08-03T00:13:27.509384Z  INFO bevy_winit: Skipped event for closed window: WindowId(00000000-0000-0000-0000-000000000000)
    thread 'Compute Task Pool (1)' panicked at 'called `Option::unwrap()` on a `None` value', C:\Users\jonah\.cargo\registry\src\github.com-1ecc6299db9ec823\bevy_flycam-0.8.0\src\lib.rs:118:44
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    thread 'main' panicked at 'task has failed', C:\Users\jonah\.cargo\registry\src\github.com-1ecc6299db9ec823\async-task-4.3.0\src\task.rs:426:45
    

    The error comes from the following code:

    fn cursor_grab(keys: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
        let window = windows.get_primary_mut().unwrap();
        if keys.just_pressed(KeyCode::Escape) {
            toggle_grab_cursor(window);
        }
    }
    

    I believe changing this to something like the following will fix this:

    fn cursor_grab(keys: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
        if let Some(window) = windows.get_primary_mut() {
            if keys.just_pressed(KeyCode::Escape) {
                toggle_grab_cursor(window);
            }
        }
    }
    

    I can fork and create a PR later, just figured it would be good to make an issue first.

    opened by JonahPlusPlus 0
  • Updated to bevy 0.7

    Updated to bevy 0.7

    Updated to bevy 0.7.0, which has now been released

    • Simplified query as raised in #14 by @tguichaoua, thanks! 🚀
    • Updated documentation and added a support section to show how bevy_flycam versions relate to which bevy version
    opened by BlackPhlox 0
  • Reduce Bevy dependencies

    Reduce Bevy dependencies

    Previously used render feature is a group that contains unneeded stuff, like bevy_ui or bevy_text. Specified features in this PR is the required minimum. You can read more about in in this issue: https://github.com/bevyengine/bevy/issues/4202

    wayland and x11 features doesn't affect on anything on platforms other then Linux. x11 feature is even enabled by default in Bevy.

    opened by Shatur 0
  • Cursor Grab won't work under macOS

    Cursor Grab won't work under macOS

    Since the update to bevy 0.9 and the according flycam version 0.9 the cursor grabbing doesn't work anymore. Instead the following error will get logged:

    ERROR bevy_winit: Unable to un/grab cursor: the requested operation is not supported by Winit
    

    The cursor is invisible while inside the window but as soon as the cursor leaves the window it appears again. According to https://github.com/bevyengine/bevy/issues/6590 it seems to be that the current mode Confined is only supported by Windows and not macOS, while Locked is only supported by macOS and not Windows.

    opened by NoFr1ends 0
  • Use yaw/pitch from Camera's rotation.

    Use yaw/pitch from Camera's rotation.

    Fixes issue with first mouse movement resetting the camera rotation. Query the yaw and pitch from the camera before updating the rotation.

    This helps with issue #17.

    opened by Neopallium 1
  • intentional position and orientation

    intentional position and orientation

    It would be nice, if the initial position and orientation could be set by the user. May be the MovementSettings could become CameraSettings? (And thank you for the crate, it gave me a fast help)

    opened by DerKarlos 3
  • Camera uses XZY instead of XYZ

    Camera uses XZY instead of XYZ

    According to the bevy-cheatbook,

    • The X axis goes from left to right (+X points right).
    • The Y axis goes from bottom to top (+Y points up).
    • The Z axis goes from far to near (+Z points towards you, out of the screen).

    I noticed, however, while using the flycam that the A & D keys slide the camera on the local X axis, W & D on the Z axis, and Shift & Space on the Y axis. Because of this, I ended up modeling my world in XZY space, which caused problems later down the line for me. Shouldn't Z be treated as the "up and down" axis, rather than Y, for the sake of consistency?

    opened by DavidCosbyUofU 2
Releases(v0.9.0)
  • v0.9.0(Nov 13, 2022)

    What's Changed

    • Removed window unwrap()s by @JonahPlusPlus in https://github.com/sburris0/bevy_flycam/pull/20
    • Updated to bevy 0.9 by @BlackPhlox in https://github.com/sburris0/bevy_flycam/pull/22

    New Contributors

    • @JonahPlusPlus made their first contribution in https://github.com/sburris0/bevy_flycam/pull/20

    Full Changelog: https://github.com/sburris0/bevy_flycam/compare/v0.8.0...v0.9.0

    Links

    crates.io : https://crates.io/crates/bevy_flycam

    Source code(tar.gz)
    Source code(zip)
  • v0.8.0(Jul 31, 2022)

    What's Changed

    • Updated to Bevy 0.8 by @DogsCodesStudio in https://github.com/sburris0/bevy_flycam/pull/18
    • Simplified scroll example by @BlackPhlox in https://github.com/BlackPhlox/bevy_flycam/pull/1, thanks for the help @superdump!

    New Contributors

    • @DogsCodesStudio made their first contribution in https://github.com/sburris0/bevy_flycam/pull/18 🚀

    Full Changelog: https://github.com/sburris0/bevy_flycam/compare/v0.7.0...v0.8.0

    Source code(tar.gz)
    Source code(zip)
  • v0.7.0(Apr 15, 2022)

    What's Changed

    • Reduce Bevy dependencies by @Shatur in https://github.com/sburris0/bevy_flycam/pull/15, nice catch!
    • Simplified query as raised in https://github.com/sburris0/bevy_flycam/issues/14 by @tguichaoua, thanks! 🚀
    • Updated to bevy 0.7 by @BlackPhlox in https://github.com/sburris0/bevy_flycam/pull/16

    New Contributors

    • @Shatur made their first contribution in https://github.com/sburris0/bevy_flycam/pull/15

    Full Changelog: https://github.com/sburris0/bevy_flycam/compare/v0.6.0...v0.7.0

    Source code(tar.gz)
    Source code(zip)
  • v0.6.0(Jan 27, 2022)

    bevy_flycam has been updated to work with Bevy's 0.6 release! Special thanks to @mnett82 for migrating the plugin to 0.6 & @bitshifter for the glam fix!

    What's Changed

    • Use normalize_or_zero to avoid a glam_assert from firing. by @bitshifter in https://github.com/sburris0/bevy_flycam/pull/10
    • Migrate to bevy v0.6 by @mnett82 in https://github.com/sburris0/bevy_flycam/pull/12
    • Prepare for 0.6 Crate Update by @BlackPhlox in https://github.com/sburris0/bevy_flycam/pull/13
      • Updated readme
      • Fixed CI for 0.6
      • Added info! to examples

    New Contributors

    • @bitshifter made their first contribution in https://github.com/sburris0/bevy_flycam/pull/10
    • @mnett82 made their first contribution in https://github.com/sburris0/bevy_flycam/pull/12

    Full Changelog: https://github.com/sburris0/bevy_flycam/compare/v0.5.1...v0.6.0

    Source code(tar.gz)
    Source code(zip)
  • v0.5.1(May 28, 2021)

  • v0.5.0(Apr 7, 2021)

    This version has been updated to work with the newly released Bevy 0.5! Huge thanks to @BlackPhlox and @HydrogenC for making this possible.

    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Feb 15, 2021)

    • Add NoCameraPlayerPlugin
    • Add note about PlayerPlugin spawning its own camera to README
    • Use init_resource instead of add_resource(Resource::default())
    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Feb 10, 2021)

  • v0.2.1(Feb 2, 2021)

  • v0.2.0(Jan 30, 2021)

    • No longer moves all Cameras, only things with FlyCam components
    • Require minimal Bevy features
    • Remove needlessly complex initial camera position
    Source code(tar.gz)
    Source code(zip)
Owner
Spencer Burris
Spencer Burris
Combine simple building blocks to create smooth cameras: first-person, chase, orbit, look-at, you name it!

?? dolly Combine simple building blocks to create smooth cameras: first-person, chase, orbit, look-at, you name it! Camera rigs made with dolly are en

Tomasz Stachowiak 284 Dec 26, 2022
First-person 3D pong ray-traced on CPU in real time.

ray ten Run in browser ray-ten.mp4 Reimagining of a 1986 ZX Spectrum game room ten made with ray tracing. Completely ignoring GPUs when rendering 3D g

Egor 2 Aug 20, 2022
A game made in one week for the Bevy engine's first game jam

¿Quien es el MechaBurro? An entry for the first Bevy game jam following the theme of "Unfair Advantage." It was made in one week using the wonderful B

mike 20 Dec 23, 2022
Minecraft-esque voxel engine prototype made with the bevy game engine. Pending bevy 0.6 release to undergo a full rewrite.

vx_bevy A voxel engine prototype made using the Bevy game engine. Goals and features Very basic worldgen Animated chunk loading (ala cube world) Optim

Lucas Arriesse 125 Dec 31, 2022
A 4X style camera for bevy.

A 4X style camera for bevy. Demo Default Key Bindings: W / A / S / D / Arrow Keys / Mouse Left - Move along the horizontal plane Q / E / Mouse Right -

null 30 Jan 4, 2023
A simple camera for properly displaying tile-based low resolution pixel perfect 2D games in bevy.

Bevy Tiled Camera A simple camera for properly displaying low resolution pixel perfect 2D games in bevy. The camera will adjust the viewport to scale

sark 10 Oct 5, 2022
Smooth pixel-perfect camera for Bevy

bevy_smooth_pixel_camera A bevy plugin that adds a simple smooth pixel camera. The smoothing is based on this video from aarthificial which explains h

Doonv 9 Nov 14, 2023
Bevy Simple Portals is a Bevy game engine plugin aimed to create portals.

Portals for Bevy Bevy Simple Portals is a Bevy game engine plugin aimed to create portals. Those portals are (for now) purely visual and can be used t

Sélène Amanita 11 May 28, 2023
2d Endless Runner Game made with Bevy Game Engine

Cute-runner A 2d Endless Runner Game made with Bevy Game Engine. Table of contents Project Infos Usage Screenshots Disclaimer Project Infos Date: Sept

JoaoMarinho 2 Jul 15, 2022
A game of snake written in Rust using the Bevy game engine, targeting WebGL2

Snake using the Bevy Game Engine Prerequisites cargo install cargo-make Build and serve WASM version Set your local ip address in Makefile.toml (loca

Michael Dorst 0 Dec 26, 2021
A Client/Server game networking plugin using QUIC, for the Bevy game engine.

Bevy Quinnet A Client/Server game networking plugin using QUIC, for the Bevy game engine. Bevy Quinnet QUIC as a game networking protocol Features Roa

Gilles Henaux 65 Feb 20, 2023
My first Real-Time 3D Game Engine learning project written in Rust.

EyeEngine-Rust FOA, sry for my poor English. What is Eye Engine? Eye Engine is my first Real-Time 3D Game Engine learning project. There are two editi

F-seeeye 4 Jan 5, 2022
My first attempt at game programming. This is a simple target shooting game built in macroquad.

sergio My first attempt at game programming. This is a simple target shooting game built in macroquad. Rules Hit a target to increase score by 1 Score

Laz 1 Jan 11, 2022
A basic web assembly chess engine written in rust.

This library is a basic implementation of a chess min-max algorithm with alpha-beta pruning (Algorithm Info). It is designed to be compiled down to WebAssembly and used for web applications.

null 2 Nov 25, 2022
Inspector plugin for the bevy game engine

bevy-inspector-egui This crate provides the ability to annotate structs with a #[derive(Inspectable)], which opens a debug interface using egui where

Jakob Hellermann 517 Dec 31, 2022
Crossterm plugin for the bevy game engine

What is bevy_crossterm? bevy_crossterm is a Bevy plugin that uses crossterm as a renderer. It provides custom components and events which allow users

null 79 Nov 2, 2022
Concise Reference Book for the Bevy Game Engine

Unofficial Bevy Cheat Book Click here to read the book! Concise reference to programming in the Bevy game engine. Covers useful syntax, features, prog

null 947 Jan 8, 2023
Proof-of-concept of getting OpenXR rendering support for Bevy game engine using gfx-rs abstractions

Introduction Proof-of-concept of getting OpenXR rendering support for Bevy game engine using gfx-rs abstractions. (hand interaction with boxes missing

Mika 52 Nov 14, 2022
A physics lib for the bevy game engine based on physme

physimple Physimple aims to be the simplest(and capable) physics engine(currently for bevy) WARNING Beware for breaking changes with each update for n

null 24 Oct 28, 2022