Rust & Wasm でミニゲームを作る時のサンプル(Rust2021)
はじめに
WebAssemblyを使いミニゲームを作成する際、WASMの作法に、Rustの借用や所有権、クロージャ、ジェネリクスなどのモダン仕様が重なると、自作アプリのビルドを通すのに苦労します。そこで、'web_bindgen'や、'web-sys'処理をPoC(試行錯誤※)するための、シンプル(1ファイルでなるべくコーディング量が少ない)なミニゲーム用の"Rust & Waws"サンプルを作成しました。また、ブラウザーからのコールバックを受け取る方法は、たくさんの情報が公開されていますが、それでも、自由に使えるようになるまで理解するには、時間がかかりました。今回のサンプルと合わせて、私が理解したイメージを掲載します。
※実際に思考錯誤した内容
- MouseやTouchイベントから座標を、画面サイズが異なる場合に取得する方法
- 画像やCSSの操作をjavascript/rustのどっちで実装する!?かの確認
- ブラウザーからのコールバック処理の受け取り方
対象のバージョン
- Rust 2021 Edition
- rustc 1.83.0
- cargo 1.80.1
- rustup 1.27.1
- pnpm 9.12.3
環境構築例:Rust & WebAssembly 構築メモ
Rust&Wasm サンプル
サンプルを通して理解した内容
-
Gameオブジェクトを "Mutable Static Variables"として用意する必要があります。理由は、Closure::wrap()に渡たすオブジェクトは全て'static'でないといけないためです。また、渡すオブジェクトを変更可能にしたいので、'Mutable Static'にする必要があります。Closureは、Strcutとほぼ同等とあり、Structが内部的に作られるイメージをもつと扱いやすくなります。👍
A closure expression produces a closure value with a unique, anonymous type that cannot be written out. A closure type is approximately equivalent to a struct which contains the captured variables.
参照:The Rust Referencehttps -
再描画時に呼び出す関数(Closure)を用意します。
- unsafe{}は、static mute のオブジェクトの値を変えるため必要になります。
- 引数として呼び出しを開始した時点の時刻が返されますが、サンプルでは参照していません。
- RC<T>を使って実装する理由は、callbackの処理中に、再帰用のrequestAnimatinoFrameを呼び出す必要があるためです。👍
Rc<T> enables multiple owners of the same data; Box<T> and RefCell<T> have single owners.
参照:RefCell<T> and the Interior Mutability Pattern
-
再描画時に呼び出される関数(Closure)を指定してrequetsAnimationFrameを呼び出します。
-
ブラウザーが、再描画のタイミングで 3.で指定した関数(Closure)を呼び出します。
-
自前の内部カウントをインクリメントし、各内部変数を更新します。
-
各内部変数を参照し、再描画します。
-
"requestAnimationFrame()"を呼び出し、次の再描画に備えます
-
クリック時にに呼び出される関数(Closure)を用意します。
-
"canvas"に、click時に呼び出されるイベント・リスナーをセットします。
-
forget()を呼び出し、関数のスコープを抜けた後でも、イベントを受け取れるように、Function(closure)のポインタ用情報を維持します。👍
-
ブラウザーが、クリックを検知し、 8.で指定した関数(Closure)を呼び出します。
-
受け取ったクリック座標を、内部変数に反映します。
Discussion