Help us understand the problem. What is going on with this article?

UnityでGameObjectにHideFlagsを設定した時の挙動まとめ

More than 1 year has passed since last update.

当初はiPhoneXのSafeArea対応のための便利スクリプトを用意する予定でしたが、その過程で調べたHideFlagsの挙動が大変興味深かったため、そちらを纏めてみました。

前提

  • Unity 2017.2.0p2 MacOS
  • シーン上のGameObjectのhideFlagsに設定する
  • "オブジェクト" = エディター上から見えるGameObjectとコンポーネントのまとまり (≒GameObject)

HideFlagsとは

HideFlagsはUnityのObjectが持つhideFlagsプロパティを設定するフラグです。
hideFlagsを設定すると、例えばオブジェクトをヒエラルキー上から不可視にしたりすることなどが出来ます。

HideFlagsの挙動

hideFlagsプロパテイ

  • GameObjectのhideFlagsに値をセットすると、その値はGameObjectの持つ全てのコンポーネントにその値が上書きされる
  • コンポーネントのhideFlagsに値をセットしても、その値はGameObjectや他のコンポーネントには影響しない
  • GameObjectにコンポーネントを追加すると、その時のGameObjectのhideFlagの値が自動的にセットされる

以下の調査はGameObjectとコンポーネントのどちらにHideFlagsをセットされた時の挙動か区別していない点に注意してください。

HideFlags.HideInHierarchy

  • オブジェクトがHierarchyビューに表示されなくなる
  • オブジェクトをSceneビューから選択できなくなる
    • スクリプトからSelection.objectに入れる事で選択状態にすることはできる

HideFlags.HideInInspector

  • コンポーネントがInspectorビューに表示されなくなる
    • オブジェクトの名前やActiveなどは表示されたまま操作可能

HideFlags.DontSaveInEditor

  • オブジェクトがシーンに保存されなくなる
  • オブジェクトを編集したり、ヒエラルキーを変更してもシーンにDirtyがつかなくなる
  • アプリをビルドしたとき、オブジェクトがシーンに含まれなくなる
    • 保存されていないシーン上で設定されていてもビルドに含まれない
    • DontSaveInBuild と同じ
  • Prefabにも保存されなくなる
    • バグでPrefabに含まれてしまうバージョンもある (Issue Tracker)
    • ルートに DontSaveInEditor が設定されたオブジェクトをPrefab化しようとするとエラーを出してくれる

HideFlags.NotEditable

  • オブジェクトを選択した時のInspectorビューの表示が全て灰色になり編集できなくなる
    • ヒエラルキーの移動は可能
    • コンポーネントの値のコピーは可能
  • Sceneビュー上でハンドルが表示されなくなる

HideFlags.DontSaveInBuild

  • アプリをビルドしたとき、オブジェクトがシーンに含まれなくなる
    • 保存されていないシーン上で設定されていてもビルドに含まれない
  • DontSaveInEditor とは異なり、シーンには保存される

HideFlags.DontUnloadUnusedAsset

  • オブジェクトやそのコンポーネントに影響は見られない

HideFlags.DontSave

  • DontSaveInBuildDontSaveInEditorDontUnloadUnusedAsset の複合

HideFlags.HideAndDontSave

  • HideInInspector 以外の全ての複合

複合的な条件下で起きる現象

以下のいずれかの条件を満たすと、オブジェクトは「シーンに属さないオブジェクト」に変化しました。

  • [条件1] シーン直下にあり、 HideInHierarchy,DontSaveInEditor,DontSaveInBuild が同時に設定される
  • [条件2] シーン直下にあり、 DontSaveInEditor が設定され、所属するシーンがアンロードされる

実験の結果、こうなったオブジェクトには以下のような特徴があるようです。

  • 通常のオブジェクトと同様に動作する
    • Sceneビュー、Gameビューにも表示される
  • Object.FindObjectOfType で取得できない
  • Scene.GetRootGameObjects で取得できない
  • GameObject.scene が無効なシーンを指す
  • シーンのアンロードで削除されない
    • リコンパイル後も削除されない
  • 選択してもGUI上から削除できない
    • 明示的なDestroyやDestroyImmediateで削除できる
  • [条件1] を満たさないHideFlagsが設定されるとその時アクティブなシーンの配下に戻る

要はリークオブジェクトになります。

消失したオブジェクトを探すには?

前述の通り、消失したオブジェクトはシーンから直接探すことはできません。
ですが、固有の名前やコンポーネントがついている場合は Resources.FindObjectsOfTypeAll から探すことができます。
ただし、エディターは内部的に同様の「シーンに属さないオブジェクト」を複数保持しているため、 GameObject.scene の値だけでこれを判別することはできません。

また、 生成時にstatic変数に参照を取っておくのは良い手ではありません。
リコンパイル時に参照が全てクリアされてしまい、リークオブジェクトとなってしまうからです。

ランタイムでも起きるのか?

DontSaveInEditor の付いたオブジェクトはビルドに含まれません。が、ビルドされたアプリであっても実行時に DontSaveInEditor をセットすることで同じ現象が再現するようです。
エディターコード外でHideFlagsを使う時はプリプロセッサで明確に処理を分けておくべきです。

バグなのか?

手元のマシンに入っているUnityで軽く試してみましたが、5.4, 5.5, 5.6, 2017.1 のいずれのバージョンでも再現しました。由緒正しい挙動のようです。

Unity Issue Tracker を調べてみると似た問題がヒットしました。
Issue Tracker - FINDOBJECTOFTYPE DOES NOT FIND GAMEOBJECT WITH HIDEFLAGS.DONTSAVE
条件が甘いですが、 Object.FindObjectOfType で取得できないのは 仕様 らしいです。
オブジェクトが消えない方を現象として報告すれば通るでしょうか?

まとめ

長年悩みのPrefabInPrefab処理や、ちょっとした便利機能のつもりで作ったシングルトン(?)クラスなど、HideFlagsを利用していそうなコードに心当たりがあれば、一度見直しをしてみる事をおすすめします。

ハックは用法用量を守って楽しいUnityライフを!

追記(2017/12/20)

初めてバグレポート送ってみました。せめて仕様かどうか判明することを期待しています。
https://issuetracker.unity3d.com/issues/gameobject-with-hideflags-dot-dontsaveineditor-is-still-visible-in-a-newly-created-scene

Shairo
aktsk
株式会社アカツキは、スマートフォンゲームの企画開発を中心に事業を展開しております。創業以来全てのゲームを内製しているため、高い技術ノウハウが蓄積されています。今後は、新規事業の立ち上げも行ってまいります。
http://aktsk.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away