バグって嫌ですよね、特に原因が特定できない場合はとても対応するのが大変だと思います。
今日は、C#がいつまでたっても上達しない私が小手先の技でOnMouseDrag()でGameObjectの駒がカメラの位置に瞬間移動するバグをやっつけた!という話をします。
目次
今までの経緯
そうなんです、Unityを始めてかれこれ8ヶ月が経とうとします。
しかし、全くプログラミング経験のない私は、相変わらずC#があまりよくわからずに、photonネットワーク対戦ゲームの製作をしています。
今のところなぜ動いているのかを根本的に理解せずして、スクリプトを組み合わせただけで、ゲームが奇跡のように成立しています。
プログラムのバックグラウンドがないものですから、的外れな考察や間違ったこともたくさん発言すると思いますが、ご容赦ください。
段々と段階を踏んで修正をしていきたいと思います。
駒が消え失せるバグを観察してみた
現在作成中のPhotonネットワーク対戦ボードゲーム「犬猫将棋」ですが、テストプレイをしている際に、駒をクリックしていると突然駒が消えました。
あれ、気のせいかなと思って、繰り返しクリックしているとたまに、駒が消えるんですね。
最初はどのタイミングでクリックすると消えるのかわからなかったのですが、繰り返すと段々と規則性が見えてきました。
どうやら、各プレイヤーのターン終了時に、駒を動かしていないプレイヤーが、駒を触っているとたまに消えることがあるということです。
もっと正確に言うならば、どうやら、アクティブプレイヤーでないプレイヤーが、駒をドラッグした状態でターンエンドを迎えると駒が消えるということが分かりました。
ただし、駒が消えたのはDestroyをあまり使ってないのと、Destroyした場合は新しい駒をInstantiateする仕様になっているので、自然な挙動とは思えませんでした。
エラーログも出ませんし、何か、見落としがありそうです。
シーンビューでバグをもっと観察してみた
この謎現象を解き明かすために、ゲームビューだけでなく、シーンビューでも3dで消える瞬間を観測してみました。
すると、どうでしょう。なんと駒がカメラの近くの平面に瞬間移動しているのが観測できました!
これは、駒についているMouse.csに書かれているメソッドのOnMouseDrag()の下記の文章のせいだ!と直感的にわかりました。
void OnMouseDrag() { Vector3 currentScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z); Vector3 currentPosition = Camera.main.ScreenToWorldPoint(currentScreenPoint) + this.offset; transform.position = currentPosition; }
どこにでもあるマウスのドラッグを検知してくれてそうなスクリプトですが、どう考えてもこれが怪しいのです。
カメラの位置、z座標の変化、どれをとっても怪しさ全開です。
瞬間移動先がどこなのかを確かめた
そこで、瞬間移動先を確かめてみると、z.座標は明後日のほうにぶっ飛んでるのですが、x.y座標はなんと消えた位置のまま変わっていないことに気づきます!
ならば、無理やりz座標だけ元の位置に戻してやるスクリプトを書けば良いかな?と思いつきました。
そこで書いたのが以下のスクリプトです。
void OnMouseDrag() { Vector3 currentScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z); Vector3 currentPosition = Camera.main.ScreenToWorldPoint(currentScreenPoint) + this.offset; if (currentPosition.z != -1.0f)//drag 対策 { currentPosition.z = -1.0f;//drag 対策 } transform.position = currentPosition; }
これによって、カメラの位置まで吹っ飛んでしまった駒が、元の位置(-1.0f)に戻ってきました。
まとめ
バグが起こった場合には再現性を特定できるまで突き詰めて観察する必要がありそうです。
ゲームビューだけでなく、シーンビューも使ったのが今回のバグの特定では役に立ちました。
今後のバグにも応用できるように頭の隅に置いておこうと思います。