Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

In cursor grab_mode: confined, how to get event for escape key pressed

A topic by Kammil created Mar 26, 2024 Views: 160 Replies: 2
Viewing posts 1 to 3

Hello, 

I am making a game in bevy I have exported a wasm build into a bindgen build and it can run in the html canvas. I can make the cursor.grab_mode = confined/locked to lock the cursor inside the game canvas. When I do so, itch(I think) will register next time the player will press "escape" key and when it does, the cursor stop being confined to the game canvas. I would like to know when that happens so I can also adjust the game flow in consequence.


Thanks,

Kam

(1 edit)

Ok I realized I can be notified in javascript because it is using the  Pointer Lock API. So I can do that :


    document.addEventListener("pointerlockchange", lockChangeAlert, false);
    function lockChangeAlert() {
      console.log("lock change alert");
}


Now I need to notify my game from the javascript.

(2 edits)

Ok so I found a way. Perhaps not efficient, but it works.

in main.rs:

use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
use serde::{Serialize, Deserialize};
use std::sync::Mutex;
#[derive(Serialize, Deserialize)]
pub struct CursorState {
    pub state: bool,
}
pub static JS_EVENT_QUEUE: Mutex<Vec<JsEvent>> = Mutex::new(Vec::new());
#[derive(Debug, Serialize, Clone)]
pub struct JsEvent(pub bool);
#[wasm_bindgen]
pub fn send_state_to_js() -> JsValue {
    let state = CursorState{ state: false };
    info!("alert getting states");
    serde_wasm_bindgen::to_value(&state).unwrap()
}
#[wasm_bindgen]
pub fn lock_change_alert(val: JsValue) {
    let state: CursorState = serde_wasm_bindgen::from_value(val).unwrap();
    info!("alert from rust: {}", state.state);
    JS_EVENT_QUEUE.lock().unwrap().push(JsEvent(state.state));
}

And then in a Update system:

    let mut event_queue = JS_EVENT_QUEUE.lock().unwrap();
    let events = event_queue.drain(..).collect::<Vec<_>>();
    for event in events {
        if !event.0{
            info!("alert cursor event");
            window.cursor = Cursor {
                visible: true,
                grab_mode: bevy::window::CursorGrabMode::None,
                ..default()
            };
        }
    }


And because for now I went for simplicity, in your index.html:

<script type="module">
    import {send_state_to_js, lock_change_alert} from './GameName.js';
document.addEventListener("pointerlockchange", lockChangeAlert, false);
    function lockChangeAlert() {
      const locked = document.pointerLockElement;
      Boolean(locked);
      console.log("lock change alert");
      let state = send_state_to_js();
      state.state = Boolean(locked);
      lock_change_alert(state);
    }
  </script>

Have fun,

Kam
edit: place code in code blocks