From 8ac0b85ed09158e4677c366ee0d89d4a5be48f78 Mon Sep 17 00:00:00 2001 From: Nickan Date: Sat, 29 Apr 2023 13:04:49 +0800 Subject: [PATCH 1/9] Implemented getting mouse delta working on wasm --- Cargo.toml | 11 ++++++++ src/lib.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 400a91a..a734fb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,17 @@ categories = ["game-engines", "game-development"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] bevy = { version = "0.10", default-features = false, features = ["bevy_render", "bevy_core_pipeline", "bevy_asset"] } +flume = "0.10.14" +wasm-bindgen = "0.2.84" [dev-dependencies] bevy = { version = "0.10", default-features = false, features = ["x11", "wayland", "bevy_pbr", "bevy_core_pipeline", "bevy_asset"] } + +[dependencies.web-sys] +version = "0.3.61" +features = [ + "Document", + "HtmlElement", + "ErrorEvent", + "Window", +] \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 8166851..4656903 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -217,6 +217,12 @@ impl Plugin for PlayerPlugin { .add_system(player_move) .add_system(player_look) .add_system(cursor_grab); + + #[cfg(target_arch = "wasm32")] + app + .insert_resource(LocalResource::default()) + .add_startup_system(startup) + .add_system(player_look_wasm); } } @@ -234,3 +240,75 @@ impl Plugin for NoCameraPlayerPlugin { .add_system(cursor_grab); } } + +fn startup(local_res: Res,) { + let send_mouse_move = local_res.send_mouse_move.clone(); + let cb = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| { + let _ = send_mouse_move.send((event.movement_x() as f32, event.movement_y() as f32)); + }) as Box); + + let window = web_sys::window().expect("no global `window` exists"); + window.set_onmousemove(Some(cb.as_ref().unchecked_ref())); + cb.forget(); +} + +fn player_look_wasm( + local_res: Res, + primary_window: Query<&Window, With>, + settings: Res, + mut state: ResMut, + motion: Res>, + mut query: Query<&mut Transform, With>, +) { + let mut delta_x = 0.0; + let mut delta_y = 0.0; + for (x, y) in local_res.recv_mouse_move.drain() { + delta_x = x; + delta_y = y; + } + if let Ok(window) = primary_window.get_single() { + for mut transform in query.iter_mut() { + let (mut yaw, mut pitch, _) = transform.rotation.to_euler(EulerRot::YXZ); + match window.cursor.grab_mode { + CursorGrabMode::None => (), + _ => { + // Using smallest of height or width ensures equal vertical and horizontal sensitivity + let window_scale = window.height().min(window.width()); + pitch -= (settings.sensitivity * delta_y * window_scale).to_radians(); + yaw -= (settings.sensitivity * delta_x * window_scale).to_radians(); + } + } + + pitch = pitch.clamp(-1.54, 1.54); + + // Order is important to prevent unintended roll + transform.rotation = + Quat::from_axis_angle(Vec3::Y, yaw) * Quat::from_axis_angle(Vec3::X, pitch); + } + } else { + warn!("Primary window not found for `player_look`!"); + } +} + +#[derive(Resource)] +struct LocalResource { + send_mouse_move: Sender<(f32, f32)>, + recv_mouse_move: Receiver<(f32, f32)>, + +} + +impl Default for LocalResource { + fn default() -> Self { + // Set to 100 to prevent panics because it is sending data while system is still loading + let (send_mouse_move, recv_mouse_move) = flume::bounded(100); + Self { + send_mouse_move: send_mouse_move, + recv_mouse_move: recv_mouse_move, + } + } +} + +use web_sys::HtmlElement; +use flume::*; +use wasm_bindgen::prelude::*; +use web_sys::ErrorEvent; \ No newline at end of file From 3d9e481075e54ad6794f3d5278e0c225b59203e5 Mon Sep 17 00:00:00 2001 From: Nickan Date: Sat, 29 Apr 2023 13:09:52 +0800 Subject: [PATCH 2/9] Implemented cursor grab when clicking on canvas --- src/lib.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 4656903..93d742e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -222,6 +222,7 @@ impl Plugin for PlayerPlugin { app .insert_resource(LocalResource::default()) .add_startup_system(startup) + .add_system(wasm_cursor_grab) .add_system(player_look_wasm); } } @@ -241,6 +242,7 @@ impl Plugin for NoCameraPlayerPlugin { } } +#[cfg(target_arch = "wasm32")] fn startup(local_res: Res,) { let send_mouse_move = local_res.send_mouse_move.clone(); let cb = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| { @@ -252,6 +254,14 @@ fn startup(local_res: Res,) { cb.forget(); } +#[cfg(target_arch = "wasm32")] +fn wasm_cursor_grab(mouse: Res>,) { + if mouse.just_pressed(MouseButton::Left) { + html_body().request_pointer_lock(); + } +} + +#[cfg(target_arch = "wasm32")] fn player_look_wasm( local_res: Res, primary_window: Query<&Window, With>, @@ -290,6 +300,15 @@ fn player_look_wasm( } } +#[cfg(target_arch = "wasm32")] +pub fn html_body() -> HtmlElement { + let window = web_sys::window().expect("no global `window` exists"); + let document = window.document().expect("should have a document on window"); + let body = document.body().expect("document should have a body"); + body +} + +#[cfg(target_arch = "wasm32")] #[derive(Resource)] struct LocalResource { send_mouse_move: Sender<(f32, f32)>, @@ -297,6 +316,7 @@ struct LocalResource { } +#[cfg(target_arch = "wasm32")] impl Default for LocalResource { fn default() -> Self { // Set to 100 to prevent panics because it is sending data while system is still loading @@ -308,6 +328,7 @@ impl Default for LocalResource { } } +#[cfg(target_arch = "wasm32")] use web_sys::HtmlElement; use flume::*; use wasm_bindgen::prelude::*; From 74095277ccbe23415d3eed5f9df69eb332d486ff Mon Sep 17 00:00:00 2001 From: Nickan Date: Sat, 29 Apr 2023 14:42:02 +0800 Subject: [PATCH 3/9] Remove all warnings --- src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 93d742e..32aa07b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -266,8 +266,6 @@ fn player_look_wasm( local_res: Res, primary_window: Query<&Window, With>, settings: Res, - mut state: ResMut, - motion: Res>, mut query: Query<&mut Transform, With>, ) { let mut delta_x = 0.0; @@ -331,5 +329,4 @@ impl Default for LocalResource { #[cfg(target_arch = "wasm32")] use web_sys::HtmlElement; use flume::*; -use wasm_bindgen::prelude::*; -use web_sys::ErrorEvent; \ No newline at end of file +use wasm_bindgen::prelude::*; \ No newline at end of file From b18ae22efb9315846439d42d3d5a745937f562d8 Mon Sep 17 00:00:00 2001 From: Nickan Date: Sat, 29 Apr 2023 17:20:30 +0800 Subject: [PATCH 4/9] Added option to toggle mouse feature --- src/lib.rs | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 32aa07b..ed14236 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -221,6 +221,7 @@ impl Plugin for PlayerPlugin { #[cfg(target_arch = "wasm32")] app .insert_resource(LocalResource::default()) + .insert_resource(WasmResource::default()) .add_startup_system(startup) .add_system(wasm_cursor_grab) .add_system(player_look_wasm); @@ -242,6 +243,25 @@ impl Plugin for NoCameraPlayerPlugin { } } + + + +#[cfg(target_arch = "wasm32")] +#[derive(Resource)] +pub struct WasmResource { + pub pointer_lock_enabled: bool, +} + +impl Default for WasmResource { + fn default() -> Self { + Self { + pointer_lock_enabled: true, + } + } +} + + + #[cfg(target_arch = "wasm32")] fn startup(local_res: Res,) { let send_mouse_move = local_res.send_mouse_move.clone(); @@ -255,9 +275,15 @@ fn startup(local_res: Res,) { } #[cfg(target_arch = "wasm32")] -fn wasm_cursor_grab(mouse: Res>,) { - if mouse.just_pressed(MouseButton::Left) { - html_body().request_pointer_lock(); +fn wasm_cursor_grab( + mouse: Res>, + wasm_res: Res, +) { + if wasm_res.pointer_lock_enabled { + if mouse.just_pressed(MouseButton::Left) { + html_body().request_pointer_lock(); + info!("Locked"); + } } } From 723e2c6eb082028f6d656fd205b09099e0475d79 Mon Sep 17 00:00:00 2001 From: Nickan Date: Tue, 2 May 2023 09:33:17 +0800 Subject: [PATCH 5/9] Refactor code, removed redundant Resource --- src/lib.rs | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ed14236..fc679c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -220,7 +220,6 @@ impl Plugin for PlayerPlugin { #[cfg(target_arch = "wasm32")] app - .insert_resource(LocalResource::default()) .insert_resource(WasmResource::default()) .add_startup_system(startup) .add_system(wasm_cursor_grab) @@ -245,26 +244,9 @@ impl Plugin for NoCameraPlayerPlugin { - -#[cfg(target_arch = "wasm32")] -#[derive(Resource)] -pub struct WasmResource { - pub pointer_lock_enabled: bool, -} - -impl Default for WasmResource { - fn default() -> Self { - Self { - pointer_lock_enabled: true, - } - } -} - - - #[cfg(target_arch = "wasm32")] -fn startup(local_res: Res,) { - let send_mouse_move = local_res.send_mouse_move.clone(); +fn startup(wasm_res: Res,) { + let send_mouse_move = wasm_res.send_mouse_move.clone(); let cb = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| { let _ = send_mouse_move.send((event.movement_x() as f32, event.movement_y() as f32)); }) as Box); @@ -282,24 +264,25 @@ fn wasm_cursor_grab( if wasm_res.pointer_lock_enabled { if mouse.just_pressed(MouseButton::Left) { html_body().request_pointer_lock(); - info!("Locked"); + // info!("Locked"); } } } #[cfg(target_arch = "wasm32")] fn player_look_wasm( - local_res: Res, + wasm_res: Res, primary_window: Query<&Window, With>, settings: Res, mut query: Query<&mut Transform, With>, ) { let mut delta_x = 0.0; let mut delta_y = 0.0; - for (x, y) in local_res.recv_mouse_move.drain() { + for (x, y) in wasm_res.recv_mouse_move.drain() { delta_x = x; delta_y = y; } + if let Ok(window) = primary_window.get_single() { for mut transform in query.iter_mut() { let (mut yaw, mut pitch, _) = transform.rotation.to_euler(EulerRot::YXZ); @@ -334,20 +317,21 @@ pub fn html_body() -> HtmlElement { #[cfg(target_arch = "wasm32")] #[derive(Resource)] -struct LocalResource { +pub struct WasmResource { send_mouse_move: Sender<(f32, f32)>, recv_mouse_move: Receiver<(f32, f32)>, - + pub pointer_lock_enabled: bool, } #[cfg(target_arch = "wasm32")] -impl Default for LocalResource { +impl Default for WasmResource { fn default() -> Self { // Set to 100 to prevent panics because it is sending data while system is still loading let (send_mouse_move, recv_mouse_move) = flume::bounded(100); Self { send_mouse_move: send_mouse_move, recv_mouse_move: recv_mouse_move, + pointer_lock_enabled: true, } } } From d06dbc770020b78a383721272371cfc3f8342e8e Mon Sep 17 00:00:00 2001 From: Nickan Date: Fri, 5 May 2023 16:36:04 +0800 Subject: [PATCH 6/9] Added wasm version for NoCameraPlayerPlugin --- src/lib.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fc679c9..2f8971e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -220,10 +220,10 @@ impl Plugin for PlayerPlugin { #[cfg(target_arch = "wasm32")] app - .insert_resource(WasmResource::default()) - .add_startup_system(startup) - .add_system(wasm_cursor_grab) - .add_system(player_look_wasm); + .insert_resource(WasmResource::default()) + .add_startup_system(startup) + .add_system(wasm_cursor_grab) + .add_system(player_look_wasm); } } @@ -239,6 +239,13 @@ impl Plugin for NoCameraPlayerPlugin { .add_system(player_move) .add_system(player_look) .add_system(cursor_grab); + + #[cfg(target_arch = "wasm32")] + app + .insert_resource(WasmResource::default()) + .add_startup_system(startup) + .add_system(wasm_cursor_grab) + .add_system(player_look_wasm); } } From 5c76f87f5af31fe3e0e57e114a81a0fb95688b79 Mon Sep 17 00:00:00 2001 From: Nico Date: Wed, 10 May 2023 14:03:48 +0800 Subject: [PATCH 7/9] Fixed looking around when pointer is not locked --- src/lib.rs | 111 +++++++++++++++++++++++++---------------------------- 1 file changed, 53 insertions(+), 58 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2f8971e..272807f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -253,14 +253,14 @@ impl Plugin for NoCameraPlayerPlugin { #[cfg(target_arch = "wasm32")] fn startup(wasm_res: Res,) { - let send_mouse_move = wasm_res.send_mouse_move.clone(); - let cb = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| { - let _ = send_mouse_move.send((event.movement_x() as f32, event.movement_y() as f32)); - }) as Box); - - let window = web_sys::window().expect("no global `window` exists"); - window.set_onmousemove(Some(cb.as_ref().unchecked_ref())); - cb.forget(); + let send_mouse_move = wasm_res.send_mouse_move.clone(); + let cb = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| { + let _ = send_mouse_move.send((event.movement_x() as f32, event.movement_y() as f32)); + }) as Box); + + let window = web_sys::window().expect("no global `window` exists"); + window.set_onmousemove(Some(cb.as_ref().unchecked_ref())); + cb.forget(); } #[cfg(target_arch = "wasm32")] @@ -268,12 +268,12 @@ fn wasm_cursor_grab( mouse: Res>, wasm_res: Res, ) { - if wasm_res.pointer_lock_enabled { - if mouse.just_pressed(MouseButton::Left) { - html_body().request_pointer_lock(); - // info!("Locked"); + if wasm_res.pointer_lock_enabled { + if mouse.just_pressed(MouseButton::Left) { + html_body().request_pointer_lock(); + info!("Locked"); + } } - } } #[cfg(target_arch = "wasm32")] @@ -283,64 +283,59 @@ fn player_look_wasm( settings: Res, mut query: Query<&mut Transform, With>, ) { - let mut delta_x = 0.0; - let mut delta_y = 0.0; - for (x, y) in wasm_res.recv_mouse_move.drain() { - delta_x = x; - delta_y = y; - } - - if let Ok(window) = primary_window.get_single() { - for mut transform in query.iter_mut() { - let (mut yaw, mut pitch, _) = transform.rotation.to_euler(EulerRot::YXZ); - match window.cursor.grab_mode { - CursorGrabMode::None => (), - _ => { - // Using smallest of height or width ensures equal vertical and horizontal sensitivity - let window_scale = window.height().min(window.width()); - pitch -= (settings.sensitivity * delta_y * window_scale).to_radians(); - yaw -= (settings.sensitivity * delta_x * window_scale).to_radians(); - } - } - - pitch = pitch.clamp(-1.54, 1.54); - - // Order is important to prevent unintended roll - transform.rotation = - Quat::from_axis_angle(Vec3::Y, yaw) * Quat::from_axis_angle(Vec3::X, pitch); - } - } else { - warn!("Primary window not found for `player_look`!"); - } + let mut delta_x = 0.0; + let mut delta_y = 0.0; + for (x, y) in wasm_res.recv_mouse_move.drain() { + delta_x = x; + delta_y = y; + } + + if let Ok(window) = primary_window.get_single() { + for mut transform in query.iter_mut() { + let (mut yaw, mut pitch, _) = transform.rotation.to_euler(EulerRot::YXZ); + + let window_scale = window.height().min(window.width()); + pitch -= (settings.sensitivity * delta_y * window_scale).to_radians(); + yaw -= (settings.sensitivity * delta_x * window_scale).to_radians(); + + pitch = pitch.clamp(-1.54, 1.54); + + // Order is important to prevent unintended roll + transform.rotation = + Quat::from_axis_angle(Vec3::Y, yaw) * Quat::from_axis_angle(Vec3::X, pitch); + } + } else { + warn!("Primary window not found for `player_look`!"); + } } #[cfg(target_arch = "wasm32")] pub fn html_body() -> HtmlElement { - let window = web_sys::window().expect("no global `window` exists"); - let document = window.document().expect("should have a document on window"); - let body = document.body().expect("document should have a body"); - body -} + let window = web_sys::window().expect("no global `window` exists"); + let document = window.document().expect("should have a document on window"); + let body = document.body().expect("document should have a body"); + body + } #[cfg(target_arch = "wasm32")] #[derive(Resource)] pub struct WasmResource { - send_mouse_move: Sender<(f32, f32)>, - recv_mouse_move: Receiver<(f32, f32)>, - pub pointer_lock_enabled: bool, + send_mouse_move: Sender<(f32, f32)>, + recv_mouse_move: Receiver<(f32, f32)>, + pub pointer_lock_enabled: bool, } #[cfg(target_arch = "wasm32")] impl Default for WasmResource { - fn default() -> Self { - // Set to 100 to prevent panics because it is sending data while system is still loading - let (send_mouse_move, recv_mouse_move) = flume::bounded(100); - Self { - send_mouse_move: send_mouse_move, - recv_mouse_move: recv_mouse_move, - pointer_lock_enabled: true, + fn default() -> Self { + // Set to 100 to prevent panics because it is sending data while system is still loading + let (send_mouse_move, recv_mouse_move) = flume::bounded(100); + Self { + send_mouse_move: send_mouse_move, + recv_mouse_move: recv_mouse_move, + pointer_lock_enabled: true, + } } - } } #[cfg(target_arch = "wasm32")] From 1cb16588d27232e108b76e1092dc2652d8aa9817 Mon Sep 17 00:00:00 2001 From: Nico Date: Sat, 20 May 2023 14:10:14 +0800 Subject: [PATCH 8/9] Added no default mouse grab --- src/lib.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 272807f..823e0df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -237,8 +237,7 @@ impl Plugin for NoCameraPlayerPlugin { .add_system(initial_grab_cursor.on_startup()) .add_system(initial_grab_on_flycam_spawn.on_startup()) .add_system(player_move) - .add_system(player_look) - .add_system(cursor_grab); + .add_system(player_look); #[cfg(target_arch = "wasm32")] app @@ -249,6 +248,23 @@ impl Plugin for NoCameraPlayerPlugin { } } +pub struct NoCameraAndGrabPlugin; +impl Plugin for NoCameraAndGrabPlugin { + fn build(&self, app: &mut App) { + app.init_resource::() + .init_resource::() + .init_resource::() + .add_system(player_move) + .add_system(player_look); + + #[cfg(target_arch = "wasm32")] + app + .insert_resource(WasmResource::default()) + .add_startup_system(startup) + .add_system(player_look_wasm); + } +} + #[cfg(target_arch = "wasm32")] From 2a38b1116193da3547f704ffe9387086f2b0530c Mon Sep 17 00:00:00 2001 From: Nickan Date: Thu, 25 May 2023 15:02:44 +0800 Subject: [PATCH 9/9] Fixed wasm and linux implementation in NoCameraAndGrabPlugin --- src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 823e0df..92ee38f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -254,8 +254,11 @@ impl Plugin for NoCameraAndGrabPlugin { app.init_resource::() .init_resource::() .init_resource::() - .add_system(player_move) - .add_system(player_look); + .add_system(player_move); + + #[cfg(not(target_arch = "wasm32"))] + app + .add_system(player_look); #[cfg(target_arch = "wasm32")] app