Unityのスクリプトで「Start関数がなぜか実行されない。。」という悩みはGoogle検索でいくつか見かけたのですが、「1回しか実行されないはずなのに、なぜか何回も実行されてしまう。。」という悩みは1件しか見かけたことがありません。(その1件も「なんか再起動したら治った」という内容)
が、私はそれで半月ほど悩みつまづき立ち止まってしまいましたので、後学のために原因と解決方法を御紹介します。
複数のスクリプトファイルにStart関数を書いた場合
Start関数の解説を読むと「ゲームの開始時に一度だけ呼び出される」というようなことが書いてありますが、実際は複数のスクリプトファイルにそれぞれStart関数が書かれることがあり、その場合は複数のStart関数が順番に実行されます。
この場合、実行順はユーザーが指定することができます。この記事で解説されています。
この場合はプログラマとしては複数のStart関数を書いている意識があることが普通なので、複数のStart関数が実行されるといっても別々の処理が最初に1回だけ実行されるということで違和感はないと思います。
1つしかStart関数がなくても複数回実行される場合
が、上記とは別に、Start関数を含む同一のスクリプトファイルを複数のオブジェクトにアタッチした場合には、アタッチした数だけStart関数が呼び出されます。(正確にはゲーム開始時にアクティブなオブジェクトにアタッチした数)
プログラマとしては1つしかStart関数を書いていないのに、1回しか実行されないはずのStart関数がなんで何回も実行されるの。。?となります。
おわりに(解決方法)
というわけで、Start関数を一つしか書いていないのに何回も実行されてしまう場合は、複数のオブジェクトにアタッチしていないか確認しましょう。
もし複数のオブジェクトにアタッチしているときはスクリプトファイルを分けて、Start関数を含むスクリプトファイルは1つのオブジェクトにしかアタッチしないようにすれば1回だけの実行で済みます。
私がはまったのは、空のオブジェクトにアタッチする監督スクリプトにStart関数・Update関数のほかボタンをOnClickしたときに呼び出される関数を多数書きこみ、それぞれボタンにアタッチしたときです。
スクリプトをまたぐと変数や関数などをGetComponent<T>();で一々呼び出さなければならなくなるので面倒ですが、UIなどのオブジェクトにアタッチするスクリプトはStart関数とは別のスクリプトファイルにしないと1度だけのつもりがアタッチした数だけStartが実行されてしまい、予期せぬ動きをしてしまいます。(エラーが出ないところがさらに厄介なのです。。)