Bloxel sandbox game similar to Minecraft "Classic" (2009) written in Rust with Bevy
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

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
}