Unity Term Book
スクリプティングとライフサイクル

Awake & Start

Awake はオブジェクト生成時に一度だけ走り(コンポーネントが無効でも実行されます)、Start は有効化後の最初のフレームで、シーン内のすべての Awake が終わってから実行されます。この実行順序を理解し、Singleton の設定とスクリプト間の安全な初期化パターンの書き方の基礎を学べます。

想像してみてください...

Awake は出勤前の個人準備——着替え、鍵を持つ、他者は不要。Start朝のキックオフ会議——全員がすでに揃っている(全 Awake 完了)ので、チーム横断の仕事を割り当てられます(GameManager.Instance、他オブジェクト検索…)。

概念の詳細

Awake() はインスタンス生成時にちょうど一度呼ばれます—— コンポーネントが enabled = false でも。内部参照に最適: _rb = GetComponent<Rigidbody>()

Start() はコンポーネントが 有効になった後の最初のフレームで走ります。シーン内のすべての Awake() が すでに終わっているため、Start は Singleton、他オブジェクト検索、イベント登録に安全です。 無効化して再有効化しても、Start は再実行されません

実行順序: Unity はまず全スクリプトの Awake、 次に全スクリプトの Start。スクリプト間の順序は未定義で、 Project Settings の Script Execution Order で指定しない限り決まりません。

ランタイム Instantiate: 生成されたオブジェクトも Awake + Start を受けます。Awake は Instantiate() が戻る前、Start は次フレームの開始時です。

スクリプト間の実行順序

⚡ AWAKE フェーズ(最初のフレーム前)

GameManager.Awake()

_instance = this

PlayerCtrl.Awake()

_rb = GetComponent()

EnemyAI.Awake()

_nav = GetComponent()

🚀 START フェーズ(最初のフレーム)

GameManager.Start()

LoadLevel(1)

PlayerCtrl.Start()

GameManager.Instance ✅

EnemyAI.Start()

FindPlayer() ✅

🔄 Update ループ(毎フレーム)

ハンズオン手順

1

Awake:自己初期化

GetComponent<T>() をキャッシュ、プライベートフィールド初期化、Singleton 設定。他オブジェクトは呼ばない。

2

Start:外界と接続

GameManager.InstanceFindObjectOfType<T>()、イベント登録を使う。

3

必要なら Script Execution Order

Edit → Project Settings → Script Execution Order → より早く走らせたいスクリプトを上へ。

4

スクリプト間の null を避ける

ScriptA.Awake がまだ Awake していない ScriptB に触ると null。横断アクセスは Start で。

インタラクティブシミュレーター

スクリプトをシーンに追加し Load Scene を押すと、各スクリプトで Awake → Start の順に発火します。

Scripts in Scene

Execution Log

スクリプトを追加して Load Scene...

Phase: Idle|最低 2 スクリプトを追加して Load Scene

コード例

基本

Awake で Singleton、他コンポーネントは Start で接続。

public class GameManager : MonoBehaviour
{
  public static GameManager Instance { get; private set; }

  void Awake()
  {
      // Singleton setup — runs before every Start()
      if (Instance != null) { Destroy(gameObject); return; }
      Instance = this;
      DontDestroyOnLoad(gameObject);
  }
}

public class PlayerController : MonoBehaviour
{
  private Rigidbody _rb;

  void Awake() => _rb = GetComponent<Rigidbody>();

  void Start()
  {
      // Safe: GameManager.Awake() already finished
      GameManager.Instance.RegisterPlayer(this);
  }
}

コード例

上級

[DefaultExecutionOrder] 属性で Awake 順序を制御する。

using UnityEngine;

// Runs before other scripts (more negative = higher priority)
[DefaultExecutionOrder(-100)]
public class ServiceLocator : MonoBehaviour
{
  public static ServiceLocator Instance { get; private set; }
  private Dictionary<System.Type, MonoBehaviour> _services = new();

  void Awake()
  {
      Instance = this;
      // Auto-register every IService in the scene
      foreach (var svc in FindObjectsOfType<MonoBehaviour>())
          if (svc is IService)
              _services[svc.GetType()] = svc;
  }

  public T Get<T>() where T : MonoBehaviour =>
      _services.TryGetValue(typeof(T), out var s) ? s as T : null;
}

// Any script can fetch a service in Start:
// var gm = ServiceLocator.Instance.Get<GameManager>();

📌 要点

  • Awake:自分を準備——他者不要
  • Start:シーンと接続——全 Awake の後
  • 有効/無効の切替で Start は再実行されない
  • 順序固定には [DefaultExecutionOrder]

⚠️ よくあるミス

  • ❌ Awake() 内で Singleton に触る

    まだ Awake していない可能性 → NullReferenceException

    ✅ Singleton へのアクセスは Start()

  • ❌ Singleton を Start() で作る

    他スクリプトの Awake 完了時にまだ無い → null

    ✅ Singleton は必ず Awake() で作る