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