• トップ
  • ブログ一覧
  • 【Unity】Destroyメソッドでオブジェクトが破棄されるタイミング
  • 【Unity】Destroyメソッドでオブジェクトが破棄されるタイミング

    Destroyメソッドの使い方について

    Unityでゲームを作る際、例えばキャラクターが弾を撃ち、敵を倒す場合、弾が敵に当たった時に弾のオブジェクトをシーン上から削除する必要が出てくるだろう。
    使い方は以下の通り。

    1
    2// 特定のオブジェクトを破棄する
    3GameObject bullet = GameObject.Find("Bullet");
    4Destroy(bullet);
    5
    6// このスクリプトがついたオブジェクトを破棄する
    7Destroy(gameObject);

    ただし、Destroyはコンポーネントも削除できるので、書き方によってはオブジェクトは残ってしまう

    1
    2// このスクリプトを破棄する(オブジェクトは残る)
    3Destroy(this);
    4
    5var canvasGroup = gameObject.GetComponent();
    6//  CanvasGroupのコンポーネントを破棄する(オブジェクトは残る)
    7Destroy(canvasGroup);

    Destroyメソッドでオブジェクトが破棄されるタイミング

    本題のDestroyメソッドでオブジェクトが破棄されるタイミングは、
    Destroyメソッドが呼ばれたフレームの最後
    ライフサイクルのOnDestroyに当たる部分になる。

    https://docs.unity3d.com/ja/2023.2/Manual/ExecutionOrder.html

    実際に検証

    コード:

    1using UnityEngine;
    2
    3コード
    4public class Gun : MonoBehaviour
    5{
    6    GameObject bullet;
    7    int frameCount;
    8
    9    void Start()
    10    {
    11         bullet = GameObject.Find("Bullet");
    12         frameCount = 0;
    13    }
    14
    15    void Update()
    16    {
    17        frameCount += 1;
    18        if (bullet != null)
    19        {
    20            // bulletがまだあったら破棄する
    21            Destroy(bullet);
    22        }
    23        
    24        // Destroy後に判定する
    25        if (bullet == null)
    26        {
    27            Debug.Log($"{frameCount}フレーム目: bullet is null");
    28        }
    29        else
    30        {
    31            Debug.Log($"{frameCount}フレーム目: bullet is not null");
    32        }
    33    }
    34}

    実行結果:

    Destroyの後のif文が、1フレーム目はbulletがnullじゃない、2フレーム目以降はbulletがnullという判定になっていることが確認できる。

    処理が多くなった際に、破棄したと思ったオブジェクトがDestroyメソッドと同一フレームでまだ破棄されておらず、オブジェクトの数にカウントされたりif文が想定通り判定されなかったりするので、注意が必要だ。

    対策としてはnullを代入するなどが考えられる

    1using UnityEngine;
    2
    3public class Gun : MonoBehaviour
    4{
    5    GameObject bullet;
    6    int frameCount;
    7
    8    void Start()
    9    {
    10         bullet = GameObject.Find("Bullet");
    11         frameCount = 0;
    12    }
    13
    14    void Update()
    15    {
    16        frameCount += 1;
    17        if (bullet != null)
    18        {
    19            // bulletがまだあったら破棄する
    20            Destroy(bullet);
    21            // 破棄したらその場でnullにする
    22            bullet = null;
    23        }
    24        
    25        // Destroy後に判定する
    26        if (bullet == null)
    27        {
    28            Debug.Log($"{frameCount}フレーム目: bullet is null");
    29        }
    30        else
    31        {
    32            Debug.Log($"{frameCount}フレーム目: bullet is not null");
    33        }
    34    }
    35}

    また、DestroyImmediateという即座に破棄されるメソッドもあるが、公式は推奨していないので、可能な限りDestroyを使おう。

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background