テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

OnDestroyの処理中にInstantateは避けるべき

先日のゲームジャムで、ゲームのシーンを終了させた時に大量のパーティクルがシーンに残るといった事案が発生しました。何が原因かと調べてみた所、パーティクル生成をOnDestroyで行っていることが原因でした。

スクリーンショット 2014-01-27 23.46.46

OnDestroyはオブジェクトが消滅したタイミングで呼ばれる命令ですが、
これの実行中にInstantiateを呼ぶとシーン再生終了時にゴミが残る事象があります。

これは例えば、こんなコードで発生します。

void OnDestroy ()
{
GameObject.Instantiate (new GameObject ("gomi"));
}

この現象が発生した祭、下のようなメッセージが表示されるので、
分かりやすいです。
Some objects were not cleaned up when closing the scene. (Did you spawn new GameObjects from OnDestroy?)

さて、この事象のそもそもの原因ですが、Unityのシーンの再生停止処理にキモがあります。

Unityはシーン再生を停止する時、シーンの状態を再生前に戻します。
これは挙動を確認する限り、シーンのオブジェクトを全て破棄し
シーン再生時の状態をロードしてるみたいです。

その為、OnDestroyにInstantate処理を記述しておくと、
破棄フェイズでゴミを生成してしまう…といった訳です。

これを回避するには、OnApplicationQuitで終了判定を取得しておき、
終了していた場合は生成しない…といった回避が必要みたいです。

Instantiate OnDestroy

private static bool isQuitting = false;

void OnApplicationQuit ()
{
isQuitting = true;
}

void OnDestroy ()
{
if (!isQuitting)
GameObject.Instantiate (new GameObject ("gomi"));
}

他の方法も探しましたが、残念ながら見つけることは出来ませんでした。


正直面倒なので、
削除する際に何かパーティクルとか生成しない方が良さそうです。