Unityのtutorialやってるけどうまくいかないねって話

  Unityにはいくつかtutorialがある。様々な種類のゲームが作れるので、どういうものが作りたいのかによって選ぶのだろう。

 

 とりあえず2DのシンプルなSTGを作成するtutorialであるSpaceShooterを選んだ。

現状ほぼ終了したが、どうしようもないバグがある。しばらく頑張ったがどうにもならなかったのでもうここでいったん諦めようと思う。これ以上追うことはとても疲れるし面倒で、ゲームを作るという本題から外れてしまっているようで、もうやる気はない(*最後に記述)。

 

 

 バグについて。

 Counting Points - 14 - Space Shooter - Unity Official Tutorials - YouTube

 この動画に沿って進める過程でバグに気づいた。(ただ、原因はもっと前の何かかもしれない)

 仕様はAsteroid(=敵)をBolt(=弾)で破壊するたびにスコアが10だけ加算される、という機能で、DestroyByContact.csとGameController.csに追記して実装する。

 実装したバグがあり結果、加算がまれに10だけ、多くの場合は20も加算されてしまう。

 これに似た例は既にある。衝突判定がまれに2回呼ばれるケースだ。

detail.chiebukuro.yahoo.co.jp

 

 しかし残念ながら、この解決方法は今回のケースには適用できない(?)。

上の記事はDestroyを使って衝突したオブジェクトを消すので、以後衝突しないという話なのだろう。

一方で今回、すでに衝突後Destroyは呼ばれている。Destroyを呼ぶという方法での解決はできないらしい。

 

 

 他に調べた結果、BoltとAsteroidの衝突でどちらも消えないことが(多くの場合)あるらしいということだ。BoltとAsteroid両方のIDをDebug.Logで衝突時に吐かせた。

おなじIDのペアの衝突が1回または2回生じている。Destroyができていないのか。

 UnityにはたくさんのObjectがあり、私が消したいものを消すようなコードが書けていないということが、注意しないとよく起きそうな印象がある(

ゲームオブジェクトの作成および削除 - Unity マニュアル

)。ちなみにObjectそのものを指すとき、Destroy(someone.gameObject);してやる。すでにそう書いている。tutorialどおりに。そもそもDestroy自体は呼ばれていてできているはずだ。1回か2回か呼ばれて、そしてシーン上から消えるのだから。

 

 さらに関連する2つのスクリプトの中身を、tutorialに入っている実装済みのスクリプトと同一のものと置き換えてもみたが、バグは消えない。つまり、スクリプトに原因はないのではないか?

 

 

 Unityの操作に誤りがあるということもあり得るだろう。こればかりはスクリプトの中身を置き換えるような、正しく動くものと置き換えてバグがあるのかないのか確かめるようなことなどはきっとできないだろうから、目視で確認した。それでも動画の内容と実装済みのプロジェクトの設定と差異はなかったように思う。しかし動画にも実装済みプロジェクトにも前述のバグはどうもないらしいのだ。いくらランダム性があるバグで、それが偶然生じないとしても体感の頻度があまりに違う。

 

 ではどこに原因があるのか。

 Unityの操作に誤りがある可能性は排除できないが、目視で探すのはばかげている。楽をするためのUnityではないのか。よって良い方法が見つかれば別だが保留。

 他にはバージョンの差異がバグの原因となりうるだろう。tutorialは2013年、もう5年も前のもので、そこそこ新しいUnityでそれを作ろうとするのは無理があるのかもしれない。事実、いくつかの関数は非推奨(Deprecated)や廃止済み(Obsoleted)であった。同様にUnityで過去に定番とされるような実装のパターンであっても、現在は非推奨であるものが、このプロジェクトに使われていない、ということは確認できていない。しかもこういうことについては警告などが出てくれないかもしれない。Destroy自体は頻繁に使う関数であるらしいので、これにバグはきっとないのではないかと思うが。。。

 

 

 Destroyはオブジェクトを削除する関数ではないらしい。フレーム更新時にオブジェクトを削除するようにフラグを建てる。これを考えるとフレーム更新前に2回呼ばれることもあるのではないか、と疑いが生まれる。

【Unity】Update()とFixedUpdate()には使い分けがあった!? - クリアメモリ

MonoBehaviour.Update() - Unity スクリプトリファレンス

MonoBehaviour.OnTriggerEnter(Collider) - Unity スクリプトリファレンス

 

このあたりを見てもあまり確信は持てない。

  • ColliderはRigidBodyではないらしいがUpdateで呼んで良いのか、
  • OnTrigger系関数はどこで呼ばれるのか、
  • 呼ばれている場所は適切な方のUpdateか、
  • これらの機能にバージョン間で差異がありバグの原因となりえるか

なんてことを調べればいいのだと思うが、とても不毛だしやらない。

私が知りたいのは快適にゲームを作る方法などであって、不快な思いをしながらUnityの実装や機能の変遷を調べることではない。

 

 今後はとりあえず参考にする情報から古いUnityのものを消したいので公式のリファレンスを見ることを増やしていこうと思うが、あまりわかりやすいとは思わないのでそれはそれでストレスが溜まりそうだ(例えばUpdateでしてはいけないこと、すべきことをどうやって公式から知ればいいのか)。

 

 (*)やる気が出ないといえば、どうもtutorialは英語の動画を見る以外なく(結果のスクリプトだけはコードで読むことができるようだが)、これはとても面倒でやる気が出ない。

 英語を聞き取って実装の意図を把握するのは難しいのでyoutubeの自動字幕を使う。口頭の情報は早いので、その字幕も早い。何度も数秒巻き戻して確認する必要がある。

 字幕は画面を隠す。具体的にはもともととても字が小さいため見にくいスクリプトの記述を隠す。バージョンの差異によるUIの変更などはAnnotationで修正案が出てくるがそれにも重複する。字幕を覚えて、字幕を消してから見直すことになる。そんな感じでゲームを作るというよりは動画の流れについていく作業という感じが強く、あまり面白くはない。テキスト状態で公開してもらえば単語検索やGoogle翻訳に投げたり、戻って単元の復習やバグ探しのために目を通す、なんてことができてすごく便利なんだな、と痛感した。ああいう動画だと講義でやったことと自分がやったつもりだができていないことを比較してバグを探すようなことが大変辛い。

 ただUnityの操作などは文章でのみ説明されるよりは画像や動画などの視覚情報で説明されると分かりやすいようにも思うので、なかなか難しいのかもしれない。