diff --git a/crates/bevy_window/src/cursor.rs b/crates/bevy_window/src/cursor.rs index c3926d1b04726..88cbcbb5b4bc9 100644 --- a/crates/bevy_window/src/cursor.rs +++ b/crates/bevy_window/src/cursor.rs @@ -1,3 +1,51 @@ +use crate::WindowId; +use bevy_math::Vec2; +use std::ops::Deref; + +#[derive(Debug, Clone, Default, Deref)] +/// Resource storing the cursor position on the app window +/// +/// ## Usage +/// +/// You can use this resource to retrieve the cursor position: +/// +/// ```rust +/// # use bevy_window::*; +/// # use bevy_ecs::prelude::*; +/// # +/// fn my_system(cursor: Res) { +/// if let Some(pos) = cursor.position() { +/// // Do something +/// } +/// } +/// ``` +/// +/// If you want both the position and window id you may do: +/// +/// ```rust +/// # use bevy_window::*; +/// # use bevy_ecs::prelude::*; +/// # +/// fn my_system(cursor: Res) { +/// if let Some((window_id, pos)) = cursor.0 { +/// // Do something +/// } +/// } +/// ``` +pub struct CursorPosition(pub Option<(WindowId, Vec2)>); + +impl CursorPosition { + /// Retrieves the cursor position from the given [`WindowId`] + pub fn position(&self) -> Option { + self.0.map(|(_, p)| p) + } + + /// Retrieves the cursor position from the *primary* window + pub fn window_id(&self) -> Option { + self.0.map(|(id, _)| id) + } +} + /// The icon to display for a window's cursor. /// /// Examples of all of these cursors can be found [here](https://www.w3schools.com/cssref/playit.asp?filename=playcss_cursor). diff --git a/crates/bevy_window/src/lib.rs b/crates/bevy_window/src/lib.rs index ca57cde6fac6b..9d71d98aeb5e3 100644 --- a/crates/bevy_window/src/lib.rs +++ b/crates/bevy_window/src/lib.rs @@ -47,6 +47,8 @@ pub struct WindowPlugin { /// If this system (or a replacement) is not running, the close button will have no effect. /// This may surprise your users. It is recommended to leave this setting as `true`. pub close_when_requested: bool, + /// Whether the plugin will update a [`CursorPosition`] resource every frame. + pub update_cursor_position: bool, } impl Default for WindowPlugin { @@ -55,6 +57,7 @@ impl Default for WindowPlugin { add_primary_window: true, exit_on_all_closed: true, close_when_requested: true, + update_cursor_position: true, } } } @@ -91,6 +94,11 @@ impl Plugin for WindowPlugin { }); } + if self.update_cursor_position { + app.init_resource::(); + app.add_system(update_cursor_position); + } + if self.exit_on_all_closed { app.add_system(exit_on_all_closed); } diff --git a/crates/bevy_window/src/system.rs b/crates/bevy_window/src/system.rs index 45a374fe2e09d..8ee42d38fb141 100644 --- a/crates/bevy_window/src/system.rs +++ b/crates/bevy_window/src/system.rs @@ -1,9 +1,16 @@ -use crate::{Window, WindowCloseRequested, WindowFocused, WindowId, Windows}; +use crate::{CursorPosition, Window, WindowCloseRequested, WindowFocused, WindowId, Windows}; use bevy_app::AppExit; use bevy_ecs::prelude::*; use bevy_input::{keyboard::KeyCode, Input}; +/// Updates the [`CursorPositions`] resource +pub fn update_cursor_position(mut positions: ResMut, windows: Res) { + positions.0 = windows + .iter() + .find_map(|w| w.cursor_position().map(|p| (w.id(), p))); +} + /// Exit the application when there are no open windows. /// /// This system is added by the [`WindowPlugin`] in the default configuration.