一、前言
在前期的實現中,我們使用 Rust 編寫核心邏輯,并通過 WebAssembly 將其引入到 Web 環境中,再利用 JavaScript 進行渲染。接下來,我們將在這一基礎上增加用戶交互功能,使模擬過程不僅能夠自動演化,還能支持用戶對細胞狀態進行手動修改。
二、實現暫停與恢復游戲
1. 在 HTML 中添加按鈕
首先,在 wasm-game-of-life/www/index.html
文件中,在 <canvas>
上方添加一個按鈕,用于控制游戲的暫停與恢復:
<button id="play-pause"></button>
2. 在 JavaScript 中管理動畫
為了控制動畫,我們需要保存 requestAnimationFrame
返回的標識符,以便后續通過 cancelAnimationFrame
取消動畫調用。在 wasm-game-of-life/www/index.js
中,新增如下代碼:
let animationId = null;// renderLoop 函數負責繪制網格、細胞并更新狀態
const renderLoop = () => {drawGrid();drawCells();universe.tick();animationId = requestAnimationFrame(renderLoop);
};// 判斷游戲是否暫停
const isPaused = () => {return animationId === null;
};const playPauseButton = document.getElementById("play-pause");// 開始游戲,設置按鈕圖標并啟動動畫
const play = () => {playPauseButton.textContent = "?";renderLoop();
};// 暫停游戲,更新按鈕圖標并取消下一幀動畫
const pause = () => {playPauseButton.textContent = "?";cancelAnimationFrame(animationId);animationId = null;
};// 根據當前狀態切換播放和暫停
playPauseButton.addEventListener("click", event => {if (isPaused()) {play();} else {pause();}
});// 初始化時調用 play() 啟動動畫
play();
通過這段代碼,我們可以根據 animationId
的狀態判斷游戲是否在播放,并相應地啟動或暫停動畫。同時,按鈕的圖標也會顯示對應的狀態。
三、實現點擊切換細胞狀態
為了讓用戶能直接在畫布上點擊修改細胞狀態,我們需要在 Rust 和 JavaScript 端分別進行處理。
1. Rust 端的修改
在 wasm-game-of-life/src/lib.rs
文件中,為 Cell
添加一個 toggle
方法,用于切換細胞狀態:
impl Cell {fn toggle(&mut self) {*self = match *self {Cell::Dead => Cell::Alive,Cell::Alive => Cell::Dead,};}
}
接著,在 Universe
的公開接口中添加 toggle_cell
方法,這樣 JavaScript 就能調用它來切換指定行列上的細胞狀態:
#[wasm_bindgen]
impl Universe {pub fn toggle_cell(&mut self, row: u32, column: u32) {let idx = self.get_index(row, column);self.cells[idx].toggle();}
}
通過 #[wasm_bindgen]
標注,該方法會被導出至 JavaScript 環境中。
2. JavaScript 端的處理
在 wasm-game-of-life/www/index.js
中,為 <canvas>
添加點擊事件監聽器,完成以下步驟:
- 獲取點擊事件相對于頁面的坐標;
- 將頁面坐標轉換為
<canvas>
內部的坐標; - 根據坐標計算出對應的行和列;
- 調用
universe.toggle_cell
切換細胞狀態; - 重新繪制網格和細胞以更新界面顯示。
具體實現如下:
canvas.addEventListener("click", event => {const boundingRect = canvas.getBoundingClientRect();const scaleX = canvas.width / boundingRect.width;const scaleY = canvas.height / boundingRect.height;const canvasLeft = (event.clientX - boundingRect.left) * scaleX;const canvasTop = (event.clientY - boundingRect.top) * scaleY;const row = Math.min(Math.floor(canvasTop / (CELL_SIZE + 1)), height - 1);const col = Math.min(Math.floor(canvasLeft / (CELL_SIZE + 1)), width - 1);universe.toggle_cell(row, col);drawGrid();drawCells();
});
通過以上代碼,當用戶點擊 <canvas>
時,就能實現對對應位置細胞狀態的即時切換,從而自由繪制自定義圖案。
四、效果預覽
完成上述步驟后,使用 wasm-pack build
重建項目,然后刷新 http://localhost:8080/
。你將會看到:
- 點擊頁面上的按鈕可以暫停或恢復游戲的動畫;
- 在暫停狀態下,點擊畫布即可改變相應位置細胞的狀態,實現自定義圖案的繪制。
五、總結
通過本文,我們實現了基于 WebAssembly 的 Game of Life 模擬的交互功能:
- 利用 JavaScript 控制動畫的暫停和恢復,使得用戶能夠在需要時停下演化過程進行編輯;
- 通過點擊
<canvas>
切換細胞狀態,讓自定義圖案的繪制變得直觀便捷。
這種前后端技術的緊密結合展示了現代 Web 開發中多技術協作的魅力,為進一步擴展和優化應用提供了堅實基礎。希望這篇博客能為你提供有價值的參考,激發你探索更多有趣的功能擴展和優化方案。
Happy coding!