Use picking system for cursor grabbing

main
copygirl 3 weeks ago
parent 1cbf30704d
commit 5467859d6d
  1. 91
      client/src/input/cursor_grab.rs
  2. 12
      client/src/main.rs

@ -1,63 +1,60 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy::input::common_conditions::input_just_pressed;
use bevy::window::{CursorGrabMode, CursorOptions}; use bevy::window::{CursorGrabMode, CursorOptions};
use crate::Screen; use crate::Screen;
pub fn plugin(app: &mut App) { 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( app.add_systems(
PreUpdate, Update,
update_cursor_grab.run_if(in_state(Screen::Gameplay)), ungrab_cursor.run_if(
is_cursor_grabbed.and(input_just_pressed(KeyCode::Escape).or(not(is_window_focused))),
),
); );
} }
fn update_cursor_grab( fn add_window_click_observer(window: Single<Entity, With<Window>>, mut commands: Commands) {
mut mouse_button_input: ResMut<ButtonInput<MouseButton>>, commands.entity(*window).observe(
key_input: Res<ButtonInput<KeyCode>>, |mut event: On<Pointer<Click>>, mut cursor: Single<&mut CursorOptions>| {
window: Single<(&mut Window, &mut CursorOptions)>, cursor.grab_mode = CursorGrabMode::Locked;
) { cursor.visible = false;
let (mut window, mut cursor) = window.into_inner(); event.propagate(false);
},
let is_grabbed = cursor.grab_mode != CursorGrabMode::None; );
let request_grab = mouse_button_input.any_just_pressed([MouseButton::Left, MouseButton::Right]); }
let request_ungrab = !window.focused || key_input.just_pressed(KeyCode::Escape);
fn ungrab_cursor(mut cursor: Single<&mut CursorOptions>) {
if !is_grabbed && request_grab && !request_ungrab { cursor.grab_mode = CursorGrabMode::None;
cursor.grab_mode = CursorGrabMode::Locked; cursor.visible = true;
}
// To prevent other systems (such as `place_break_blocks`)
// from seeing the mouse button inputs, clear the state here. /// Sets the cursor position to the center of the window,
mouse_button_input.clear(); /// so that once it is ungrabbed, it will reappear there.
} fn center_cursor(mut window: Single<&mut Window>) {
let center = window.resolution.size() / 2.;
if is_grabbed && request_ungrab && !request_grab {
cursor.grab_mode = CursorGrabMode::None; // 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
if is_grabbed && !request_ungrab { // on `PreUpdate`, so it runs with one frame delay.
// Set the cursor position to the center of the window, so that when //
// it is ungrabbed, it will reappear there. Because `is_grabbed` is // On X11, the cursor can't be locked into place, only confined to the
// not updated on grab, this block is delayed by one frame. // window bounds, so we repeatedly move the cursor back to the center
// // while it's grabbed.
// On Wayland, since the cursor is locked into place, this only needs //
// to be done once. Unfortunately, for some reason this doesn't work // On the web, the cursor can be locked, but setting its position isn't
// in the same frame as setting `grab_mode`, and would log an error. // supported at all, so this would instead log a bunch of errors.
// #[cfg(not(target_family = "wasm"))]
// On X11, the cursor can't be locked into place, only confined to the window.set_cursor_position(Some(center));
// 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 is
// not supported at all, so this would instead log a bunch of errors.
let center = window.resolution.size() / 2.;
#[cfg(not(target_family = "wasm"))] // skip on web
window.set_cursor_position(Some(center));
}
// Keep cursor visbility in sync with `grab_mode`.
cursor.visible = cursor.grab_mode == CursorGrabMode::None;
} }
pub fn is_cursor_grabbed(cursor: Single<&CursorOptions>) -> bool { pub fn is_cursor_grabbed(cursor: Single<&CursorOptions>) -> bool {
cursor.grab_mode != CursorGrabMode::None cursor.grab_mode != CursorGrabMode::None
} }
pub fn is_window_focused(window: Single<&Window>) -> bool {
window.focused
}

@ -26,7 +26,7 @@ fn main() -> Result {
let mut app = App::new(); let mut app = App::new();
app.insert_resource(args); app.insert_resource(args);
app.add_plugins( app.add_plugins((
DefaultPlugins DefaultPlugins
.set(WindowPlugin { .set(WindowPlugin {
primary_window: Some(Window { primary_window: Some(Window {
@ -47,10 +47,16 @@ fn main() -> Result {
meta_check: AssetMetaCheck::Never, meta_check: AssetMetaCheck::Never,
..default() ..default()
}), }),
); bevy_fix_cursor_unlock_web::FixPointerUnlockPlugin,
));
// Make entities require the `Pickable` component if
// they should be considered for the picking system.
app.insert_resource(UiPickingSettings {
require_markers: true,
});
app.add_plugins(( app.add_plugins((
bevy_fix_cursor_unlock_web::FixPointerUnlockPlugin,
common::assets::plugin, common::assets::plugin,
common::network::plugin, common::network::plugin,
assets::plugin, assets::plugin,

Loading…
Cancel
Save