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.
74 lines
2.6 KiB
74 lines
2.6 KiB
use bevy::prelude::*; |
|
|
|
use bevy::input::common_conditions::input_just_pressed; |
|
use bevy::picking::pointer::{PointerId, PointerLocation}; |
|
use bevy::window::{CursorGrabMode, CursorOptions}; |
|
|
|
use crate::Screen; |
|
|
|
pub fn plugin(app: &mut App) { |
|
app.add_systems(OnEnter(Screen::Gameplay), add_window_click_observer); |
|
app.add_systems(PreUpdate, center_cursor.run_if(is_cursor_grabbed)); |
|
app.add_systems( |
|
Update, |
|
ungrab_cursor.run_if( |
|
is_cursor_grabbed.and(input_just_pressed(KeyCode::Escape).or(not(is_window_focused))), |
|
), |
|
); |
|
} |
|
|
|
fn add_window_click_observer(window: Single<Entity, With<Window>>, mut commands: Commands) { |
|
commands.entity(*window).observe( |
|
|mut event: On<Pointer<Click>>, mut cursor: Single<&mut CursorOptions>| { |
|
cursor.grab_mode = CursorGrabMode::Locked; |
|
cursor.visible = false; |
|
event.propagate(false); |
|
}, |
|
); |
|
} |
|
|
|
fn ungrab_cursor(mut cursor: Single<&mut CursorOptions>) { |
|
cursor.grab_mode = CursorGrabMode::None; |
|
cursor.visible = true; |
|
} |
|
|
|
/// Sets the cursor (and pointer) position to the center of the |
|
/// window, so that once it is ungrabbed, it will reappear there. |
|
fn center_cursor( |
|
mut window: Single<&mut Window>, |
|
pointers: Query<(&PointerId, &mut PointerLocation)>, |
|
) { |
|
let center = window.resolution.size() / 2.; |
|
|
|
// On Wayland, since the cursor is locked into place, this only needs to be |
|
// done once. Unfortunately, for some reason, this doesn't work in the same |
|
// frame as setting `grab_mode`, logging an error. This system is scheduled |
|
// on `PreUpdate`, so it runs with one frame delay. |
|
// |
|
// On X11, the cursor can't be locked into place, only confined to the |
|
// window bounds, so we repeatedly move the cursor back to the center |
|
// while it's grabbed. |
|
// |
|
// On the web, the cursor can be locked, but setting its position isn't |
|
// supported at all, so this would instead log a bunch of errors. |
|
#[cfg(not(target_family = "wasm"))] |
|
window.set_cursor_position(Some(center)); |
|
|
|
// Update the `PointerLocation` for the mouse to be at the center |
|
// of the window. Otherwise it might use the last known position. |
|
for (id, mut pointer) in pointers { |
|
if id.is_mouse() { |
|
if let Some(location) = pointer.location.as_mut() { |
|
location.position = center; |
|
} |
|
} |
|
} |
|
} |
|
|
|
pub fn is_cursor_grabbed(cursor: Single<&CursorOptions>) -> bool { |
|
cursor.grab_mode != CursorGrabMode::None |
|
} |
|
|
|
pub fn is_window_focused(window: Single<&Window>) -> bool { |
|
window.focused |
|
}
|
|
|