(:3[kanのメモ帳]

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

(:3[kanのメモ帳]

Hierarchy上の非アクティブなオブジェクトを検索し、取得する方法【Unity】


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

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


はじめに

GameObject.Findを使うとHierarchy上のオブジェクトを名前で検索する事ができますが、

(子に配置されているものだったら、transform.Findでも可)

//Targetという名前のGameObjectを検索し、取得(なければnull)
Debug.Log(GameObject.Find("Target"));
f:id:kan_kikuchi:20190810053030j:plain


残念ながら、アクティブじゃないオブジェクトは検索できません。

f:id:kan_kikuchi:20190810053122j:plain


という事で今回は、Hierarchy上の非アクティブなオブジェクトを検索し、取得する方法の紹介です!


なお、GameObject.Findしかり、こういう検索系の処理は重いので、

使い所を(出来るなら使わない方向で)考える必要がある点には注意が必要です。


FindObjectsOfTypeAll

非アクティブなオブジェクトを検索し、取得したい場合は、

Resources.FindObjectsOfTypeAllを使います。


なお、FindObjectsOfTypeAllはオブジェクト名でなくタイプを指定して取得するので、

以下のようにGameObjectを全て取得し、その中から名前が一致するものを探す感じになります。

//GameObjectを全て取得
var gameObjectList = Resources.FindObjectsOfTypeAll<GameObject>();

//取得したGameObjectの中からTargetを探す
foreach (var go in gameObjectList) {
  if (go.name == "Target") {
    Debug.Log("ターゲット! : " + go);
  }
}
f:id:kan_kikuchi:20190811075036j:plain


ただし、エディタ上だとHierarchy上だけでなくProject上のPrefabも取得してしまいます。

f:id:kan_kikuchi:20190811075106j:plain


なので、AssetDatabase.GetAssetOrScenePathを使って

取得したものが、どこのものなのか判定する必要があります。

Debug.Log(AssetDatabase.GetAssetOrScenePath(gameObjectInHierarchy));
f:id:kan_kikuchi:20190811075900j:plain


なお、AssetDatabaseとそれを使うためのusing UnityEditorはエディタ上でしか使えないので、

UNITY_EDITORで囲む必要もあります。まとめると以下のような感じ。

#if UNITY_EDITOR
using UnityEditor; //AssetDatabaseを使うために必要
#endif
//GameObjectを全て取得
var gameObjectList = Resources.FindObjectsOfTypeAll<GameObject>();
    
//取得したGameObjectの中からTargetを探す
foreach (var gameObjectInHierarchy in gameObjectList) {
      
  #if UNITY_EDITOR
  //Hierarchy上のものでなければスルー
  if (!AssetDatabase.GetAssetOrScenePath(gameObjectInHierarchy).Contains(".unity")) {
    continue;
  }
  #endif
  
  if (gameObjectInHierarchy.name == "Target") {
    Debug.Log("ターゲット! : " + gameObjectInHierarchy);
  }
}
f:id:kan_kikuchi:20190811080026j:plain


ちなみにLINQを使って以下のように実装する事も可能です。

var target = Resources.FindObjectsOfTypeAll<GameObject>() //GameObjectを全て取得
#if UNITY_EDITOR
.Where(go => AssetDatabase.GetAssetOrScenePath(go).Contains(".unity")) //Hierarchy上のものだけ選別
#endif
.First(go => go.name == "Target"); //Targetという名前のものを取得