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

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
};
}