Use picking system for cursor grabbing

main
copygirl 3 weeks ago
parent 1cbf30704d
commit 5467859d6d
  1. 71
      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)>,
) {
let (mut window, mut cursor) = window.into_inner();
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);
if !is_grabbed && request_grab && !request_ungrab {
cursor.grab_mode = CursorGrabMode::Locked; cursor.grab_mode = CursorGrabMode::Locked;
cursor.visible = false;
event.propagate(false);
},
);
}
// To prevent other systems (such as `place_break_blocks`) fn ungrab_cursor(mut cursor: Single<&mut CursorOptions>) {
// from seeing the mouse button inputs, clear the state here.
mouse_button_input.clear();
}
if is_grabbed && request_ungrab && !request_grab {
cursor.grab_mode = CursorGrabMode::None; cursor.grab_mode = CursorGrabMode::None;
} cursor.visible = true;
}
if is_grabbed && !request_ungrab { /// Sets the cursor position to the center of the window,
// Set the cursor position to the center of the window, so that when /// so that once it is ungrabbed, it will reappear there.
// it is ungrabbed, it will reappear there. Because `is_grabbed` is fn center_cursor(mut window: Single<&mut Window>) {
// not updated on grab, this block is delayed by one frame. let center = window.resolution.size() / 2.;
//
// On Wayland, since the cursor is locked into place, this only needs // On Wayland, since the cursor is locked into place, this only needs to be
// to be done once. Unfortunately, for some reason this doesn't work // done once. Unfortunately, for some reason, this doesn't work in the same
// in the same frame as setting `grab_mode`, and would log an error. // 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 // 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 // window bounds, so we repeatedly move the cursor back to the center
// while it's grabbed. // while it's grabbed.
// //
// On the web, the cursor can be locked, but setting its position is // On the web, the cursor can be locked, but setting its position isn't
// not supported at all, so this would instead log a bunch of errors. // supported at all, so this would instead log a bunch of errors.
let center = window.resolution.size() / 2.; #[cfg(not(target_family = "wasm"))]
#[cfg(not(target_family = "wasm"))] // skip on web
window.set_cursor_position(Some(center)); 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