mirror of
https://github.com/Xevion/Pac-Man.git
synced 2026-01-31 08:25:06 -06:00
feat(web): implement game lifecycle management for SPA navigation
Add stop_game and restart_game FFI functions to properly pause/resume the game loop during page transitions, preventing resource leaks and audio issues when navigating between pages
This commit is contained in:
@@ -46,6 +46,51 @@ pub extern "C" fn start_game() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Called from JavaScript when navigating away from the game page.
|
||||
/// Stops the Emscripten main loop and halts all audio.
|
||||
#[cfg(target_os = "emscripten")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn stop_game() {
|
||||
tracing::info!("Stopping game loop and halting audio");
|
||||
unsafe {
|
||||
platform::emscripten_cancel_main_loop();
|
||||
sdl2::mixer::Channel::all().halt();
|
||||
}
|
||||
}
|
||||
|
||||
/// Called from JavaScript to restart the game after navigating back.
|
||||
/// Creates a fresh App instance with the new canvas and starts the main loop.
|
||||
#[cfg(target_os = "emscripten")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn restart_game() {
|
||||
use std::ptr;
|
||||
|
||||
tracing::info!("Restarting game with fresh App instance");
|
||||
|
||||
unsafe {
|
||||
// Drop old App to clean up resources
|
||||
APP = None;
|
||||
|
||||
// Reinitialize audio subsystem for fresh state
|
||||
sdl2::mixer::close_audio();
|
||||
|
||||
// Create fresh App with new canvas
|
||||
match App::new() {
|
||||
Ok(app) => {
|
||||
APP = Some(app);
|
||||
tracing::info!("Game restarted successfully");
|
||||
|
||||
// Signal ready and start the main loop
|
||||
platform::run_script("if (window.pacmanReady) window.pacmanReady()");
|
||||
platform::emscripten_set_main_loop_arg(main_loop_callback, ptr::null_mut(), 0, 1);
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to restart game: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Emscripten main loop callback - runs once per frame
|
||||
#[cfg(target_os = "emscripten")]
|
||||
unsafe extern "C" fn main_loop_callback(_arg: *mut std::ffi::c_void) {
|
||||
|
||||
@@ -25,6 +25,10 @@ extern "C" {
|
||||
/// - `simulate_infinite_loop`: if 1, never returns (standard for games)
|
||||
pub fn emscripten_set_main_loop_arg(func: EmMainLoopCallback, arg: *mut c_void, fps: c_int, simulate_infinite_loop: c_int);
|
||||
|
||||
/// Cancel the currently running main loop.
|
||||
/// After calling this, the loop callback will no longer be invoked.
|
||||
pub fn emscripten_cancel_main_loop();
|
||||
|
||||
/// Execute JavaScript code from Rust
|
||||
fn emscripten_run_script(script: *const i8);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user