5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

DontDestroyOnLoadのGameObjectを列挙する

Posted at

シーンに配置されているもの一覧

開発中のデバッグにおいて、今のシーンに配置されているGameObjectの一覧を取得したいことがあります。
UnityEditor上でならばHierarchy上にあるものを見れば済むわけですが、やっぱり実機上で何が起こっているのかを知りたいわけです。
このとき、普通のシーン上に配置されているものなら以下のコードで取得できます。

getCurrent
// 現在のHierarchyのRootにあるGameObjectの一覧
var currentSceneGameObjects = SceneManager.GetActiveScene().GetRootGameObjects();

DontDestroyOnLoadの一覧

普通のやつはそれでいいのですが、DontDestroyOnLoadに登録されたGameObjectを取得するAPIはありません。
実機でしか動作しないSDKが動的にテキトーに作成するGameObjectや、タイミングによって実機でしか起きない事象などを解析する場合など、どうしても実機上でDontDestroyOnLoadの一覧が取りたい場合があります。
というわけで、以下のような回避策で取得することができました。

workaround
// まずDontDestroyOnLoadされたGameObjectを作る
var go = new GameObject(string.Empty);
Object.DontDestroyOnLoad(go);
// DontDestroyOnLoadはSceneの一種なので,GameObject.sceneから取得することができる
var dontDestroyOnLoadGameObjects = go.scene.GetRootGameObjects();

解析用コード

これを利用してこんな解析用のコードを作ってみました。
このファイルをプロジェクトに入れておくだけで、シーン遷移のたびに、シーン名と合わせてDontDestroyOnLoadの一覧をログに出力してくれます。
CollectDontDestroyOnLoad()publicにしておいたので、好きなときにGameObjectの配列を取得することもできます。

gist

DontDestroyOnLoadCollector
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Nekomimi.Daimao
{
    public class DontDestroyOnLoadCollector
    {
        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
        private static void Register()
        {
            SceneManager.sceneLoaded += (scene, mode) =>
            {
                var ddol = CollectDontDestroyOnLoad();
                var separator = ", ";
                var s = string.Join(separator, ddol.Where(go => go != null).Select(go => go.name));
                Debug.Log($"DDOL_{scene.name} : {s}");
            };
        }

        public static GameObject[] CollectDontDestroyOnLoad()
        {
            var go = new GameObject(string.Empty);
            Object.DontDestroyOnLoad(go);
            var ddol = go.scene.GetRootGameObjects();
            Object.Destroy(go);
            return ddol.Where(o => o != null && !string.Equals(o.name, string.Empty)).ToArray();
        }
    }
}

実機での動作について

How can I get all DontDestroyOnLoad GameObjects?
ここの解答をもとに作ったのですが、Editorでしか動かないことが強調されています。

works only in the Editor

また、その根拠として示されている公式ドキュメントでも以下のような記載があります。

You do not have access to the DontDestroyOnLoad scene and it is not available at runtime.

でも私が試したところではAndroidでもiOSでも実機にブッこんだら動きました
UnityEditorのバージョンは2018と2019です。下のバージョンは覚えてない。
AndroidiOSでしか試してませんが、この分だと他のプラットフォームでも動きそうな気がします。
公式ができねえ! と言ってることをやってるので、使用範囲はあくまでもデバッグにとどめたほうがよいとは思いますが。

まとめ

先人の解答を参考にしつつも、とりあえず自分で数発殴ってみることは重要だなって思いました。
あと普通に考えて公式がそういうAPI用意してくれてもよくない……? って! 思いました!
DontDestroyOnLoadって状態の権化みたいなものなのでできるだけ使わないのがベストプラクティスな気もしますが。でも使っちゃうね。しょうがないね。

おしまい。

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?