Unityで「StartにGetComponentを書くとNullになる」理由と対処

広告


Unityでよくあるトラブルとして、

StartでGetComponentしたのに、OnTriggerでNullReferenceExceptionが出る

という現象があります。

特に「プレハブをInstantiateして使う場合」に発生しやすいため、
実行順序を正しく理解しておくことが重要です。


想定する状況

  • プレハブにスクリプトをアタッチしている
  • スポナーから Instantiate() で生成する
  • Start() で GetComponent() を行っている
  • OnTriggerEnter() 内でその参照を使用している

実行順序

Unityでは、オブジェクト生成時の処理は次の順序で実行されます。

Instantiate
↓
Awake()
↓
OnEnable()
↓
(この時点で物理イベントが発生する可能性あり)
↓
Start()

ここで重要なのは、

OnTriggerEnterはStartより前に呼ばれる可能性がある

という点です。


問題が発生するコード

private AudioSource audioSource;

private void Start()
{
    audioSource = GetComponent<AudioSource>();
}

private void OnTriggerEnter(Collider other)
{
    audioSource.Play(); // nullの可能性あり
}

この場合、OnTriggerEnter が Start より先に呼ばれると
audioSource は未取得のままとなり、例外が発生します。


正しい実装

private AudioSource audioSource;

private void Awake()
{
    audioSource = GetComponent<AudioSource>();
}

private void OnTriggerEnter(Collider other)
{
    audioSource.Play();
}

Awake は Start より先に必ず実行されるため、
この問題を回避できます。


使い分けの基準

処理の内容によって、記述場所を整理すると以下のようになります。

処理内容記述場所
GetComponentAwake
自分自身の初期化Awake
他オブジェクトとの連携Start
初期状態の設定Start

なぜInstantiateで発生しやすいのか

シーンに配置されたオブジェクトでは、
すべての Awake → Start が順番に実行されるため、問題が表面化しにくくなります。

一方で、Instantiate() の場合は

  • 生成直後に Awake が実行される
  • その後すぐに物理判定が行われる
  • Start はその後に実行される

という流れになるため、
OnTriggerEnter が先に呼ばれるケースが発生します。


補足(防御的な書き方)

private void OnTriggerEnter(Collider other)
{
    if (audioSource == null) return;

    audioSource.Play();
}

実行順序の理解に加え、
このような防御コードを入れておくとトラブルを減らせます。


まとめ

  • OnTriggerEnter は Start より先に呼ばれる可能性がある
  • Start で取得した参照は未初期化のまま使われることがある
  • GetComponent は Awake に書くのが安全

この内容は、プレハブ生成を扱う際の基本的な注意点です。
特に「動的生成+物理イベント」を扱う場合は、必ず意識して実装する必要があります。

訪問数 12 回, 今日の訪問数 12回

広告

Unity

Posted by hidepon