Best Practices for Communicating Between Bevy ECS and JavaScript: Events and Global Mutex? #10172
Replies: 2 comments 3 replies
-
i've been working on this same problem. I haven't found a better way to communicate from JavaScript to Rust, but a bevy system can call a JS function just fine. here's some code from my actual project (permalink) // with the way vite-plugin-wasm-pack works, modules are relative to the js project root (i.e., next to package.json)
#[wasm_bindgen(raw_module = "./src/vtt/renderer_interface")]
extern "C" {
pub fn get_ships() -> Option<Vec<ShipObject>>;
pub fn get_ship(uuid: String) -> Option<ShipObject>;
pub fn update_primary_selection(uuid: String);
}
/// handle clicks on ships and set their `selected` field
pub fn handle_ship_click(
//
mut click: EventReader<GridClickInside>,
mut ships: Query<(&mut Ship, &GridTransform)>,
kb: Res<Input<KeyCode>>,
) {
if kb.pressed(KeyCode::Q) {
// clicking while holding Q
// another system handles burn-changing
return;
}
for event in click.iter() {
for (mut ship, trans) in ships.iter_mut() {
if trans.hex == event.location {
info!("clicked on ship at {:?}", event);
ship.selected = !ship.selected;
if ship.selected {
update_primary_selection(ship.uuid.to_string());
}
break;
}
}
}
} |
Beta Was this translation helpful? Give feedback.
-
If your use case is only Bevy -> JS, than you could possibly get away with just sending a simple string over. In my case all I want is to save some data to local storage before unload. I decided to just buffer the game state every second and write that on In js: // Buffer game state
let bufferedGameState = {};
window.buffer_game_state = function(json) {
try {
bufferedGameState = JSON.parse(json);
} catch (e) {
console.error("Invalid state JSON:", e);
}
};
// Save game before unloading the page
window.addEventListener('beforeunload', () => {
for (const [key, value] of Object.entries(bufferedGameState)) {
localStorage.setItem(key, value);
}
}); and in Bevy I run the following (scheduled to run once a second in my case): #[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = window)]
fn buffer_game_state(json: &str);
}
#[cfg(target_arch = "wasm32")]
fn sync_state_to_js(
core: Res<ProgressionCore>,
map_data: Res<MapData>,
q_player: Query<&Transform, With<Player>>,
) {
let Ok(player_transform) = q_player.single() else {
return;
};
let data = package_save_data(&core, &map_data, &player_transform);
let save_data: HashMap<&&str, &String> = WASM_KEYS.iter().zip(data.iter()).collect();
buffer_game_state(
&serde_json::to_string(&save_data).expect("failed to parse hashmap save data to json"),
);
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
👋 Hello everyone,
I'm exploring how to efficiently communicate between the
Bevy ECS
and the outside world (Javascript
in this case).I'm interested in passing events both ways -> getting events from the
Javascript
layer into theECS
,and also emitting events from the
ECS
to theJavascript
layer.In my current implementation I use a global
Mutex<Vec<JsEvent>>
, like so:And then draining this queue in a
wasm-bound
function.But I was wondering whether there is a "better" way
or what the recommended way to make such communication happen is?
Thanks for any insights :)
Beta Was this translation helpful? Give feedback.
All reactions