Unityの関数AwakeとStartの違いと現状のプログラミングの問題点

今回はゲームの機能を作成するのではなく、AwakeとStartの違いと現状のプログラミングの仕方の問題点を見ていきます。

元々準備されている関数でAwakeとStartというものがあります。
この二つは同じタイミングで実行されるような気がしますが、実は違います。

わたしの場合あまり気にせずすべてStart関数で変数の初期化、ゲームオブジェクトの取得を行っていました。
なぜそうしているかと言うと、購入した本の中で他に設定しているゲームオブジェクトを取得する際は、Awakeだと初期化処理がまだ行われておらず取得出来ない可能性があるので、Start関数内でやると良いと書いてあったからです。

変数とゲームオブジェクトを同じ扱いにしていました・・・・・(^_^;)

スポンサーリンク

AwakeとStartの違いをマニュアルで調べる

Unityのマニュアルを見てみると、

・AwakeはStart関数の前およびプレハブのインスタンス化直後(ゲームオブジェクトが有効である事)
・Startは最初のUpdateフレームが呼び出される前

となっています。
Awakeの方が先に呼び出されるんですね、なら変数の初期化はAwakeの方が良さそうです。
ゲームオブジェクトの取得はStart内が良さそうです。

AwakeとStartの違いをテストスクリプトを作成し検証する

Unityのチュートリアルでもありますが、AwakeとStartの実行順序確認の為、以下のスクリプトを用意して、試してみます。

awake1

ちゃんとAwakeが先に表示されます。
このAwakeなんですが、実はスクリプトが非アクティブでも実行されます。

awake2

上のように設定したスクリプトのチェックを外し非アクティブ(enabledがfalseの状態)にしておきます。
Unityの実行ボタンを押して確認してみます。

awake3

上のようにスクリプトを非アクティブにしていてもAwake関数は呼ばれます。

awake4

ただ上のようにスクリプトを設定しているゲームオブジェクトのチェックを外し、非アクティブ(activeSelfがfalse)にしていた場合ゲームオブジェクトがアクティブにならないとAwake関数は呼ばれません。

ゲーム実行中にゲームオブジェクトをアクティブにするとスクリプトのアクティブの状態にかかわらずAwake関数が呼ばれます。

現状のプログラミングの問題点

ここで現状のわたくしのプログラミングの問題点について考える必要が出てきました。
Start関数内でゲームオブジェクトの取得はいいとして、他オブジェクトに設定されたコンポーネントの取得も同じようにしていいんだろうか?という事です。

なぜこのように思ったかというと、時々Start関数内で他オブジェクトのコンポーネントを取得している個所でエラーが発生する為です。

エラーの内容はゲームオブジェクトやコンポーネントの取得が出来ていないという事でした。

Unityを一旦終了し、再起動するとエラーが消えたので、Unityのバグかな?とも思っていたんですが、ゲームオブジェクトやコンポーネントの取得の方法が原因のような気がしてきました。

他ゲームオブジェクトに設定しているスクリプトを取得するスクリプトを別のゲームオブジェクトのStart関数内に記述しているとしたら、他ゲームオブジェクトのスクリプトのStart関数内での初期化→取得するスクリプトのStart関数で取得の順番で実行されなければいけませんが、もし逆の順番でStart関数が実行されたらデータの初期化が完了していない状態になるんでしょうか?

でもそれであればデータが入ってないとしてもコンポーネントの取得は出来そうな気もしますが・・・。
Start関数が実行されるタイミングで他のゲームオブジェクトのロードが終わっていない事もあるんでしょうか?

ここら辺がよくわかりません。

Start関数内で普通に他オブジェクトのスクリプトは取得するはずですし・・・(^_^;)
他ゲームオブジェクトのスクリプトを取得する際に、GameObject.FindWithTagでタグの名前でゲームオブジェクトを検索し、そのゲームオブジェクトに設定しているスクリプトを取得している個所でたまにエラーが発生したりします。

いつも出るエラーではないので、対処が難しく再起動で対処してましたが、
別の方法を模索してみます。

FindWithTagで探すとダメなのかと思い探すゲームオブジェクトをpublicで指定してそこからスクリプトを取得する。
これで対処出来るなら大丈夫かも。

エラーがいつも出るわけではないので、対処出来たのかどうかもわからずじまいです。

コンポーネントを取得出来ていない原因で考えられるのがもう一つ、JavaScriptが動的型付けだからかも、Unityで使うJavaScriptは型を指定しますが、通常のJavaScriptは型を臨機応変に
変更していきます。

その型変換がうまくいかずに取得出来なかった可能性もあります。
それに対応する為にはコンポーネントの取得の記述方法を変えます。

status = GameObject.FindWithTag(“Player”).GetComponent(MyStatus); // 今までの取得方法

status = GameObject.FindWithTag(“Player”).GetComponent.<MyStatus>(); // 型を指定した取得方法

以前の記事

Unityのコンソールに表示されるスクリプトの警告文の内容を見て修正する
Unityのコンソールタブに表示される警告の意味を理解し、警告表示をなくしていきます

でGetComponentで取得する型はComponent型だと言いましたが、その型変換がうまくいっていなかったのかもしれません。

つまり現状の対処としては

・GetComponent(取得するコンポーネント) as 型
・GetComponent.<取得するコンポーネント>();

の二つの対処方法がいいと思われます。
エラーの原因が型の問題だった時の対処法になりますけどね・・・。
またエラーが出たら何か考えます・・・・・(+_+)

その後、同様のエラーが出ました。結局原因が解らずじまいです。
原因がわからないとモヤモヤしますね・・・・・(__)