Add camera look controls

main
copygirl 1 week ago
parent 7f359336ab
commit a78d113952
  1. 71
      src/free_camera.rs
  2. 5
      src/main.rs

@ -0,0 +1,71 @@
use std::f32::consts::TAU;
use bevy::input::mouse::AccumulatedMouseMotion;
use bevy::prelude::*;
use bevy::window::{CursorGrabMode, CursorOptions};
#[derive(Component, Debug)]
pub struct CameraFreeLook {
/// The mouse sensitivity, in radians per pixel.
pub sensitivity: Vec2,
/// How far the camera can be tilted up and down.
pub pitch_limit: std::ops::RangeInclusive<f32>,
/// Upon initialization, `pitch` and `yaw` will
/// be set from the camera transform's rotation.
initialized: bool,
/// The current yaw (right/left) of the camera, in radians.
pub yaw: f32,
/// The current pitch (tilt) of the camera, in radians.
pub pitch: f32,
}
impl Default for CameraFreeLook {
fn default() -> Self {
Self {
sensitivity: Vec2::splat(0.2).map(f32::to_radians),
pitch_limit: -(TAU / 4.0)..=(TAU / 4.0),
initialized: false,
yaw: 0.0,
pitch: 0.0,
}
}
}
pub fn camera_free_look(
window: Single<(&Window, &mut CursorOptions)>,
accumulated_mouse_motion: Res<AccumulatedMouseMotion>,
mouse_button_input: Res<ButtonInput<MouseButton>>,
key_input: Res<ButtonInput<KeyCode>>,
camera: Single<(&mut Transform, &mut CameraFreeLook)>,
) {
let (window, mut cursor) = window.into_inner();
let (mut transform, mut camera) = camera.into_inner();
if !window.focused || key_input.just_pressed(KeyCode::Escape) {
cursor.grab_mode = CursorGrabMode::None;
cursor.visible = true;
}
if mouse_button_input.any_just_pressed([MouseButton::Left, MouseButton::Right]) {
cursor.grab_mode = CursorGrabMode::Locked;
cursor.visible = false;
}
if cursor.grab_mode == CursorGrabMode::Locked {
// Ensure the yaw and pitch are initialized once
// from the camera transform's current rotation.
if !camera.initialized {
(camera.yaw, camera.pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
camera.initialized = true;
}
// Update the current camera state's internal yaw and pitch.
let delta = accumulated_mouse_motion.delta * camera.sensitivity;
let (min, max) = camera.pitch_limit.clone().into_inner();
camera.yaw = (camera.yaw - delta.x).rem_euclid(TAU); // keep within 0°..360°
camera.pitch = (camera.pitch - delta.y).clamp(min, max);
// Override the camera transform's rotation.
transform.rotation = Quat::from_euler(EulerRot::ZYX, 0.0, camera.yaw, camera.pitch);
}
}

@ -1,9 +1,13 @@
use bevy::prelude::*;
mod free_camera;
use free_camera::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, camera_free_look)
.run();
}
@ -36,5 +40,6 @@ fn setup(
commands.spawn((
Camera3d::default(),
Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
CameraFreeLook::default(),
));
}

Loading…
Cancel
Save