Use picking system for cursor grabbing

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

@ -1,63 +1,60 @@
use bevy::prelude::*;
use bevy::input::common_conditions::input_just_pressed;
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(
PreUpdate,
update_cursor_grab.run_if(in_state(Screen::Gameplay)),
Update,
ungrab_cursor.run_if(
is_cursor_grabbed.and(input_just_pressed(KeyCode::Escape).or(not(is_window_focused))),
),
);
}
fn update_cursor_grab(
mut mouse_button_input: ResMut<ButtonInput<MouseButton>>,
key_input: Res<ButtonInput<KeyCode>>,
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 {
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;
// To prevent other systems (such as `place_break_blocks`)
// from seeing the mouse button inputs, clear the state here.
mouse_button_input.clear();
cursor.visible = false;
event.propagate(false);
},
);
}
if is_grabbed && request_ungrab && !request_grab {
fn ungrab_cursor(mut cursor: Single<&mut CursorOptions>) {
cursor.grab_mode = CursorGrabMode::None;
cursor.visible = true;
}
if is_grabbed && !request_ungrab {
// Set the cursor position to the center of the window, so that when
// it is ungrabbed, it will reappear there. Because `is_grabbed` is
// not updated on grab, this block is delayed by one frame.
//
// 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`, and would log an error.
/// Sets the cursor 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>) {
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 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
// 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));
}
// Keep cursor visbility in sync with `grab_mode`.
cursor.visible = cursor.grab_mode == CursorGrabMode::None;
}
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
}

@ -26,7 +26,7 @@ fn main() -> Result {
let mut app = App::new();
app.insert_resource(args);
app.add_plugins(
app.add_plugins((
DefaultPlugins
.set(WindowPlugin {
primary_window: Some(Window {
@ -47,10 +47,16 @@ fn main() -> Result {
meta_check: AssetMetaCheck::Never,
..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((
bevy_fix_cursor_unlock_web::FixPointerUnlockPlugin,
common::assets::plugin,
common::network::plugin,
assets::plugin,

Loading…
Cancel
Save