Unityの初期化処理 AwakeとStartの違いについて

新しい機能を作りたいときによくMonoBehaviorを継承して頻繁に作りますが

初期化方法として

  • Awake
  • Start

の2つがあると思いますが今回はこれらの違いを見ていきたいと思います。

コンテンツ

AwakeとStartの違い

初期化に使うAwakeとStartの違いは大まかに言えば処理が走るタイミングが異なる点です。

公式ドキュメントによるとこの様になっています。

普通に使用する場合このような順序となっていますね。

Awake

Start

一見するとAwakeのほうが最速で処理されるので便利そうに見えまね

Awakeの特徴と欠点

Awake特徴として

  • 最速で実行される
  • Awakeを実装したスクリプトを設定したオブジェクトが非表示の場合でも実行される
  • Awake時に他のオブジェクトの処理がまだされていないので、他のオブジェクトの取得する   最高のタイミングとなる

↓Hobby

Awakeのときに使用回数をセットし遊ぶたびに使用回数が減っていく



public class Hobby : Monobehavior
{
    // 使用可能回数
    private int m_usage = 0;

    void Awake()
    {
         m_usage = 10;
    }

    public void GetUsage()
    {
        return m_usage;
    }

    public void Play()
    {
        if(m_usage > 0)
        {
            m_usage--;
            return 1;
        }
        else
        {
            return 0;
        }
    }
}

主なHobbyの使用者としては以下がいるとします。

↓ ジャイアニスト

[RequireComponent(typeof(Hobby))]
public class Jaianist : Monobehavior
{
    private Hobby m_myHobby = null; 

    void Awake()
    {
        m_myHobby = GetComponent<Hobby>();
    }

    void Update() 
    {
       if(m_myHobby != null)
       {
            m_myHobby.Play();
            if(m_myHobby.GetUsage() == 0)
            {
                Destroy(m_myHobby.gameobject);
                m_myHobby = null;
            }
       }
    }
}

「ジャイアニスト」スクリプトがWakeで最速にHobbyを取得しUpdateで遊んでますね…

使用回数がになったら捨ててますしね。

[RequireComponent(typeof(Hobby))]

これ使用すること Jaianist を使用するときは同じオブジェクトに Hobby を設定しなければないらないので。

GetComponent<Hobby>() の保証がかなり担保されるので。

GetComponent を使う際は使用することをおすすめします。

これだけでもかなり便利ですが欠点として

  • Awakeが複数ある場合どの順番で実行されるか不明
  • Awakeを実装したスクリプトを設定したオブジェクトが非表示の場合でも実行される
  • Awake時に初期化が終わっていないほかオブジェクトの値を変更すると最悪ゲームが止まる

例えばこんな感じですね


引き続きジャイアにスト
public class Jaianist : Monobehavior
{
    private Hobby m_myHobby = null; 

    void Awake()
    {
        m_myHobby = GameObject.Find<RichBoy>("RichBoy").Rental();
        m_myHobby.Play();
        if(m_myHobby.GetUsage() == 0)
        {
            Destroy(m_myHobby.gameobject);
            m_myHobby = null;
        }
    }
}


Hobbyを持っているRichBoy
[RequireComponent(typeof(Hobby))] 
public class RichBoy : Monobehavior
{
    private int m_happyCounter = 0;

    public Hobby Rental()
    {
        return transform.Find("Hobby").GetComponent<Hobby>();
    }

    void Update()
    {
       Rental.Play();
    }
}

今度も Hobbyを取得しUpdateで遊んでますね…

しかし挙動としては

  • 「ジャイアニスト」スクリプトがWakeで最速に「RichBoy」からHobbyを取得
  • 「ジャイアニスト」スクリプトがAwake時にHobbyを遊び使用できなくなったら破棄

普通はこんなスクリプトは絶対に書いてはいけません

この場合 「ジャイアニスト」スクリプト が一度遊んでいますが 「ジャイアニスト」がAwake時に遊んだときの「Hobby」は初期化できているのでしょうか?

答えは不明です。

ですのでできていない場合は 「ジャイアニスト」がAwakeのタイミングで破棄しているため。

「RichBoy」はHobbyを遊ぶことができなくなりますね。

Startの特徴と欠点

Startの特徴としては

  • Updateの直前で処理される
  • Awakeを実装したスクリプトを設定したオブジェクトが非表示の場合では実行されない

Awakeとは違いオブジェクトが非表示の場合はそのオブジェクトがSetActiveなどで表示状態にならなければ実行されません。

ですので初期化の意味合いとしては若干違う雰囲気がしますね。

更に以下のようなスクリプトの場合

public class Product : MonoBehavior
{
   void Start()
   {
       Debug.Log("Start");
   }

    public void Init()
    {
        Debug.Log("Init");
    }
}


public class Creater : MonoBehavior
{
    private Product m_baseProduct = null;

    void Update()
    {
       var product = Instatiate(m_baseProduct);
       product.Init();
    }
}



見ての通り「Creater」が毎フレーム「Product」生成してますが

この場合

StartよりもInitが先に処理されます。

そのため、Startは必ず呼ばれるものでもなく最速ではない点に注意しましょう。

まとめ

MonoBehaviorを継承したオブジェクトの方法のStartとAwakeの差を見てみましたが、

同じ最初に呼ばれるものでも大きく挙動が異なることわかります。

ですので初期化の際は以下に注意しましょう。

  • AwakeではGetComponentなどオブジェクトの参照取得に使う
  • Awakeでは自身の値の初期化に留める
  • Awakeでは外部オブジェクトの値の参照や変更は絶対に避ける
  • Startは呼ばれない可能性がある

また、どうしても順番を担保して安全に初期化をしたい場合は、このように

自分でInitを呼び手動初期化するのも全然ありかと思います。



public class Creater : MonoBehavior
{
    private Product m_baseProduct = null;

    void Update()
    {
       var product = Instatiate(m_baseProduct);
       product.Init();
    }
}



public class Product : MonoBehavior
{
    public void Init()
    {
        Debug.Log("Init");
    }
}

このように、それぞれの適材適所があるのでうまく使い分けていきましょう。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT US
vuniformity誰でもない人
トレンドの行く末を見守っている
仮名を名乗るエンジニア

ゲーム開発は仕事であり趣味である
プログラムだけでなく多種多様なスキルを数多く持つ

ゲーム開発は
ソーシャルゲームを開発運用の経験アリ
ゲーム以外にも経験アリ
Webサービス保守開発等に携わる

ゲームプレイの主な戦場は
FGO
FEH
MTGA
マビノギ
ここでは主にunityroomで公開しているゲーム作り直しの軌跡を綴っていきます