(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]


本ブログの運営者kan.kikuchiが個人で開発したゲームです!


Unity6.4からDestroy時に呼ばれるOnDisableのタイミングが微妙に変わってる件【Unity】


このエントリーをはてなブックマークに追加


この記事でのバージョン
Unity 6000.3.4f1
Unity 6000.4.5f1


はじめに

UnityのMonoBehaviourにはコンポーネントが無効になった時や、

GameObjectが非アクティブになった時に呼ばれるOnDisableというメソッドがあります。



OnDisableでログが出るようして確認してみると以下のような感じに。

private void OnDisable() {
  Debug.Log($"OnDisable : {name}");
}


このOnDisableはDestroyされた際にも呼ばれるのですが、

その挙動がUnity6.4から微妙に変わったようなので今回はその紹介です!


Destroy時に呼ばれるOnDisableのタイミングが微妙に変わってる件

公式の発表によると以下の通りですが、これも微妙に間違っていて

Changed OnDisable behavior
Unity now correctly invokes OnDisable callbacks on components of a GameObject
’s descendants when you destroy a GameObject using Object.Destroy.

Previously, OnDisable was only invoked for components on the GameObject itself and its direct children. This change makes Object.Destroy behavior consistent with Object.DestroyImmediate, which has always invoked OnDisable across the entire hierarchy.

If you added workarounds to manually propagate OnDisable to deeper descendants, they will now cause duplicate calls and must be removed.

(AI翻訳)

Unity は、Object.Destroy を使用して GameObject を破棄する際、その GameObject の子孫に含まれるコンポーネントに対しても、OnDisable コールバックを正しく呼び出すようになりました。

以前は、OnDisable はその GameObject 自体と直接の子オブジェクト上のコンポーネントに対してのみ呼び出されていました。この変更により、Object.Destroy の挙動は、これまで常に階層全体に対して OnDisable を呼び出していた Object.DestroyImmediate と一貫したものになります。

深い階層の子孫に対して OnDisable を手動で伝播させる回避策を追加していた場合、今後は重複して呼び出される原因となるため、その回避策を削除する必要があります。


正しくはUnity6.3までは親をDestroyすると、子も孫もOnDisableが呼ばれるものの、

孫以降はOnDisableがちょっと遅れていました。

[SerializeField]
private GameObject _target;//ここにParentを設定

//=================================================================================
//初期化
//=================================================================================

private void Start() {
  Debug.Log($"Destroy開始 : {_target.name}");
  Destroy(_target);
  Debug.Log($"Destroy終了 : {_target.name}");
}


それがUnity6.4からは孫以降もOnDisableのタイミングが揃うようになりました。

(ドキュメントにはないがParentが最後になるように順番も変わったぽい)


ちなみに以前からDestroyImmediateで削除した場合は(実行される順番も含めて)この挙動だったので、

DestroyImmediateと挙動が揃い、元々想定していた正しい挙動になったようです。


あまり影響が出る事は少なそうな変更かもしれませんが、

前の仕様前提で実装してると場合によって気付きにくいバグを生む事になるので、

知っておくともしもの時に約立つ感じの情報でした。