Three.js Cannon.es 調査資料 - 非同期処理時の地図データ更新
この記事のスナップショット
(スナップショットは特にありません..)
関連するソースは以前の記事「マップ分割(3)3Dデータ」のものになります。
ソース「マップ分割(3)3Dデータ」
概要
データファイルをバイナリ化して同期処理させるために async/await をつけました。
動作の途中、地図データ更新(データファイルを読み込む)のために処理が止まっている想定だったのに裏で動いていておかしな挙動に。
結果から言うと、requestAnimationFrame() がループの先頭にあったために変な挙動になっていて、ループの最後にもってくれば期待したとおりの挙動に。
やったこと
物理計算やレンダリングを一定間隔で繰り返し行うため requestAnimationFrame() を使うのですが、これを関数の先頭に置いていたために期待しない挙動、マップを移動させたときに車が何かにぶつかるような挙動をしていていました。
async function animate() {
requestAnimationFrame(animate)
world.step(timeStep);
レンダリング();
if (中央のブロックから自車がはみ出た?) {
中央のブロック内に引き戻す座標操作();
地図データ更新();
}
}
感覚的には requestAnimationFrame() で処理がフォークされ、新しいプロセス/スレッドが作成されて、引数にある関数animateが実行されるイメージでしょうか。
[animate:000] [animate:001] [animate:002]
| requestAnimationFrame() :
| ---------------------------> |requestAnimationFrame() :
| | ---------------------------> |
| | | ...
| world.step() | |
| | world.step() |
| ... | |
| | (こちらで処理が走ってしまう) | (こちらで処理が走ってしまう)
|(地図データ更新で一時停止) |
上記の状態だと、animate:000で一時停止させているつもりでも、animate:001 や animate:002 で処理が進んでしまうのでおかしな挙動になっていたのかと予想。
requestAnimationFrame を末尾に持ってきた場合は期待した通りの結果になりました。
animete:000 の一時停止で止まった後に requestAnimationFrame() で新しい animete:001 が走り出すので期待した結果になっているのかと。
async function animate() {
world.step(timeStep);
...
requestAnimationFrame(animate)
}
[animate:000] [animate:001] [animate:002]
| : :
| world.step() : :
| : :
| ... : :
| : :
|(地図データ更新で一時停止) : :
| : :
| requestAnimationFrame() : :
| ---------------------------> | :
| | world.step() :
x | :
以前の記事「マップ分割(3)3Dデータ」では、上記のとおりに修正済みです。
感想
requestAnimationFrame() に気づくまで、あれこれ悩んで console.log を入れまくりました。
非同期処理/スレッド処理は..手ごわいですね。(意地を張って、難しいとは言わない)
バイナリデータにする前、テキストデータを扱っていた時に「失敗していたコード」でも期待通りに動いていたのは async を 付けていなかったから なんですかね?
見切り発車で着手、勉強不足なことが露呈しましたが、解決できたので良しとします。(汗
Discussion