//! A freecam-style camera controller plugin. //! To use in your own application: //! - Copy the code for the [`CameraControllerPlugin`] and add the plugin to your App. //! - Attach the [`CameraController`] component to an entity with a [`Camera3dBundle`]. use bevy::input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel}; use bevy::prelude::*; use bevy::window::CursorGrabMode; use std::{f32::consts::*, fmt}; pub struct CameraControllerPlugin; impl Plugin for CameraControllerPlugin { fn build(&self, app: &mut App) { app.add_systems(Update, run_camera_controller); } } /// Based on Valorant's default sensitivity, not entirely sure why it is exactly 1.0 / 180.0, /// but I'm guessing it is a misunderstanding between degrees/radians and then sticking with /// it because it felt nice. pub const RADIANS_PER_DOT: f32 = 1.0 / 180.0; #[derive(Component)] pub struct CameraController { pub enabled: bool, pub initialized: bool, pub sensitivity: f32, pub key_forward: KeyCode, pub key_back: KeyCode, pub key_left: KeyCode, pub key_right: KeyCode, pub key_up: KeyCode, pub key_down: KeyCode, pub key_run: KeyCode, pub mouse_key_cursor_grab: MouseButton, pub keyboard_key_toggle_cursor_grab: KeyCode, pub walk_speed: f32, pub run_speed: f32, pub scroll_factor: f32, pub friction: f32, pub pitch: f32, pub yaw: f32, pub velocity: Vec3, } impl Default for CameraController { fn default() -> Self { Self { enabled: true, initialized: false, sensitivity: 1.0, key_forward: KeyCode::KeyW, key_back: KeyCode::KeyS, key_left: KeyCode::KeyA, key_right: KeyCode::KeyD, key_up: KeyCode::KeyE, key_down: KeyCode::KeyQ, key_run: KeyCode::ShiftLeft, mouse_key_cursor_grab: MouseButton::Left, keyboard_key_toggle_cursor_grab: KeyCode::KeyM, walk_speed: 5.0, run_speed: 15.0, scroll_factor: 0.1, friction: 0.5, pitch: 0.0, yaw: 0.0, velocity: Vec3::ZERO, } } } impl fmt::Display for CameraController { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, " Freecam Controls: Mouse\t- Move camera orientation Scroll\t- Adjust movement speed {:?}\t- Hold to grab cursor {:?}\t- Toggle cursor grab {:?} & {:?}\t- Fly forward & backwards {:?} & {:?}\t- Fly sideways left & right {:?} & {:?}\t- Fly up & down {:?}\t- Fly faster while held", self.mouse_key_cursor_grab, self.keyboard_key_toggle_cursor_grab, self.key_forward, self.key_back, self.key_left, self.key_right, self.key_up, self.key_down, self.key_run, ) } } #[allow(clippy::too_many_arguments)] fn run_camera_controller( time: Res