歩き方がおかしくなるバグ

歩き方がおかしくなるバグ

このバグは v0.36.6 で修正されました teramotodaiki

プレイヤーの walk が毎フレーム実行されて、歩き始めた状態がずっと続いてしまうバグ
一度でもマップを移動した場合にしか発生しない (後述)

原因
本来時間的に重なってはいけない非同期処理 (=walk) が時間的に重なってしまったせいで、始まってすぐ中断されていたから
より詳細に言うと、「歩いているかどうか」を表す状態変数が 2 つ存在し、歩き終わった瞬間だけはその 2 つの整合性が合わなくなるバグがあったから
状態変数の 1 つは behavior で、behavior が idle であれば walk でき、それ以外は walk できない
もう1つは walkingObjects という WeakSet で、元々は locate された直後に walk をキャンセルするために、歩き続けている間だけ参照を保持していた(歩いている途中に locate すると位置が戻るバグを起こさないため)
ログで確認したところ、behavior が idle になってから walkingObjects から delete されるまで間があることが分かった
これは resolve のあと Promise::then は同期的にコールされないから
これはログから得られた状況から推測した結果だが、コルーチンの実行順などの細部までは検証できていない

どうやって非同期処理 (walk) が重ならないようにするか?
1. 複数の変数が不整合が起きないよう、全ての変数が同期的に (≒同時に) 変更されるようにする
2. 状態を表す変数を 1 つにする ( walkingObjects をなくす)
2 の方がシンプルになる
唯一の問題点は、歩いている途中に locate すると位置が戻るバグを他の方法で解決する必要があること

マップを移動した場合にしか発生しない理由
マップを移動するとプレイヤーの onenterframe が3回ずつ呼ばれている
walkImpl は、3回ずつコールされて、3フレーム目に2回コールされたところで generator から抜けている
this.parentNode.childNodes のログを出力すると、プレイヤーの参照は残ったまま、 Proxy の参照が増えていた
RPGMap::load の中で if (Hack.player) this.scene.addChild(Hack.player); されていた
「プレイヤーのマップを移動したら map.load() される」という流れと、「 map.load() されたときにプレイヤーのマップを移動する」という流れがある
前者は必要だが、後者はいらなくないか?
ひとまず Hack.player は Proxy が代入されていることが分かったので、後方互換性を保つため if (Hack.player) this.scene.addChild(Hack.player.reverseProxy) に変更した
ところで、なんで2回じゃなくて3回だったんだろう。測り方が間違っていたのだろうか… teramotodaiki
Powered by Helpfeel