You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.4 KiB
124 lines
3.4 KiB
use bevy::{input::mouse::AccumulatedMouseMotion, prelude::*, window::CursorGrabMode}; |
|
|
|
const MOVEMENT_SPEED: f32 = 0.15; |
|
const MOUSE_SENSITIVITY: Vec2 = Vec2::new(0.002, 0.002); |
|
|
|
pub struct CameraControllerPlugin; |
|
|
|
/// Marks an entity as being the camera controlled by this plugin. |
|
#[derive(Component)] |
|
pub struct ControlledCamera; |
|
|
|
impl Plugin for CameraControllerPlugin { |
|
fn build(&self, app: &mut App) { |
|
app.add_systems( |
|
Update, |
|
( |
|
capture_mouse, |
|
camera_mouse_rotation, |
|
camera_keyboard_translation, |
|
) |
|
.chain(), |
|
); |
|
} |
|
} |
|
|
|
fn capture_mouse( |
|
mut window: Single<&mut Window>, |
|
mouse: Res<ButtonInput<MouseButton>>, |
|
key: Res<ButtonInput<KeyCode>>, |
|
) { |
|
if mouse.just_pressed(MouseButton::Left) { |
|
set_mouse_grabbed(&mut window, true); |
|
} |
|
if key.just_pressed(KeyCode::Escape) { |
|
set_mouse_grabbed(&mut window, false); |
|
} |
|
// Ungrab the mouse if window doesn't have focus. |
|
if !window.focused { |
|
set_mouse_grabbed(&mut window, false); |
|
} |
|
} |
|
|
|
fn camera_mouse_rotation( |
|
window: Single<&Window>, |
|
mut camera: Query<&mut Transform, With<ControlledCamera>>, |
|
mouse_motion: Res<AccumulatedMouseMotion>, |
|
) { |
|
// Mouse must be grabbed by the window for this system to run. |
|
if !mouse_grabbed(&window) { |
|
return; |
|
} |
|
|
|
// We also need to have exactly one camera with the `ControlledCamera` component. |
|
let Ok(mut transform) = camera.get_single_mut() else { |
|
return; |
|
}; |
|
|
|
let delta = mouse_motion.delta; |
|
if delta != Vec2::ZERO { |
|
let delta_yaw = -delta.x * MOUSE_SENSITIVITY.x; |
|
let delta_pitch = -delta.y * MOUSE_SENSITIVITY.y; |
|
|
|
let rot_yaw = Quat::from_axis_angle(Vec3::Y, delta_yaw); |
|
let rot_pitch = Quat::from_axis_angle(Vec3::X, delta_pitch); |
|
transform.rotation = rot_yaw * transform.rotation * rot_pitch; |
|
} |
|
} |
|
|
|
fn camera_keyboard_translation( |
|
window: Single<&Window>, |
|
mut camera: Query<&mut Transform, With<ControlledCamera>>, |
|
key: Res<ButtonInput<KeyCode>>, |
|
) { |
|
// Mouse must be grabbed by the window for this system to run. |
|
if !mouse_grabbed(&window) { |
|
return; |
|
} |
|
|
|
// We also need to have exactly one camera with the `ControlledCamera` component. |
|
let Ok(mut transform) = camera.get_single_mut() else { |
|
return; |
|
}; |
|
|
|
let mut input = Vec2::ZERO; |
|
if key.pressed(KeyCode::KeyD) { |
|
input.x += 1.; |
|
} |
|
if key.pressed(KeyCode::KeyA) { |
|
input.x -= 1.; |
|
} |
|
if key.pressed(KeyCode::KeyW) { |
|
input.y += 1.; |
|
} |
|
if key.pressed(KeyCode::KeyS) { |
|
input.y -= 1.; |
|
} |
|
|
|
let mut movement = input * MOVEMENT_SPEED; |
|
if key.pressed(KeyCode::ShiftLeft) { |
|
movement *= 4.; |
|
} |
|
|
|
if movement.x != 0. { |
|
let translation = transform.right() * movement.x; |
|
transform.translation += translation; |
|
} |
|
if movement.y != 0. { |
|
let translation = transform.forward() * movement.y; |
|
transform.translation += translation; |
|
} |
|
} |
|
|
|
fn mouse_grabbed(window: &Window) -> bool { |
|
window.cursor_options.grab_mode == CursorGrabMode::Locked |
|
} |
|
|
|
fn set_mouse_grabbed(window: &mut Window, value: bool) { |
|
window.cursor_options.visible = !value; |
|
window.cursor_options.grab_mode = if value { |
|
CursorGrabMode::Locked |
|
} else { |
|
CursorGrabMode::None |
|
}; |
|
}
|
|
|