UnityのメソッドAwakeとStartの違い

記事内に広告が含まれています。

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

通常のクラスはMonoBehaviourを継承してクラスを作成していますが、MonoBehaviourで用意されているメソッドでAwakeとStartというものがあります。
この二つは同じタイミングで実行されるような気がしますが、実は違います。

わたしの場合あまり気にせずすべてStartメソッドで変数の初期化、ゲームオブジェクトの取得を行っていました。

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

スポンサーリンク

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

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

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

となっています。

Awakeの方が先に呼び出されるんですね、ならフィールドの初期化はAwakeの方が良さそうです。

Awakeでは他のスクリプトやゲームオブジェクトの参照を取得するのはいいですが、参照先のAwakeの処理が終わってない可能性がある為、値の取得はやらない方がいいみたいです。

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

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

awake1

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

awake2

上のように設定したスクリプトのチェックを外し非アクティブ(enabledがfalseの状態)にしておきます。

Unityの実行ボタンを押して確認してみます。

awake3

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

awake4

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

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

コンポーネント取得の際の注意

スクリプトを取りつけたゲームオブジェクトがあり、そのスクリプトのStartメソッド内でコンポーネントの取得をしているとします。

しかし、UIなど最初から表示したくないゲームオブジェクトはインスペクタでチェックを外して配置している事もあります。

そんな時に外部のスクリプトからそのUIをアクティブにし、メソッド内でStartメソッド内で取得するはずのコンポーネントにアクセスしようとするとエラーになる可能性があります。

試しにMainCameraにTest2というスクリプトを作り取りつけます。

マウスの左ボタンを押したらインスペクタで設定したゲームオブジェクトをアクティブにし、そのゲームオブジェクトに設定されているGetComponentTestメソッドを呼びます。

Directional LightゲームオブジェクトにTestスクリプトを作り取りつけます。

Startメソッド内でLightコンポーネントの取得をします。

GetComponentTestメソッドでは取得したコンポーネントの名前を出力しています。

これでサンプルが出来ました。

まずはDirectional Lightをアクティブの状態でUnityを実行しマウスの左ボタンを押します。

DirectinalLightをアクティブにして実行

最初にAwake、次にStartが実行された後に画面内でマウスの左ボタンを押すとライトの名前が表示されます。

次にDirectional Lightを非アクティブにしてUnityを実行します。

DirectionalLightを非アクティブにして実行

Directional Lightが非アクティブの為、最初は何も表示されません。

その後、画面内でマウスの左ボタンを押すとメソッドが実行されますが、Startメソッドの前にGetComponentTestメソッドが呼ばれてしまいlightフィールドにはNullが設定されています。

このようにアクティブにした直後にそのスクリプトのメソッド内でStartメソッドで取得するはずのコンポーネントを使おうと思うと取得出来ていない場合があります(今はエラーが出ないかも?)。

その為、最初に非アクティブにしたゲームオブジェクトのスクリプトではその中で使うコンポーネントを実行するメソッド内で再度取得するようにした方がいいかもしれません。

OnEnableメソッドを使う

先ほどのスクリプトだとNull参照になってしまいますが、Directional Lightゲームオブジェクトに設定したTestスクリプトにOnEnableメソッドを作成し、そこで自身のLightコンポーネントを取得するようにすればエラーが発生しません。

OnEnableはMonoBehaviourクラスで定義されているメソッドでゲームオブジェクトがアクティブになった時に実行されます。

↑のようにしておくとDirectional Lightがアクティブになった時にLightコンポーネントを取得するのでエラーになりません。

OnEnableに関しては

UnityのOnEnable、OnDisable、OnDestroyメソッドについて
UnityのOnEnable、OnDisable、OnDestroyメソッドの実行タイミングについて見ていきます。

↑も参照してみてください。

参考サイト

UnityスクリプトリファレンスーMonoBehaviour.Awake()ー

UnityスクリプトリファレンスーMonoBehaviour.Start()ー

タイトルとURLをコピーしました