- 2020/11/11 【Unity】【エディタ拡張】ヒエラルキー(シーン)の Image, RawImage に使われている画像(Texture)を検出するエディタ拡張(ツール)
- 2020/11/10 【Unity】【C#】ヒエラルキー(シーン)の全てのオブジェクト(Transform)をスキャンして処理をする
- 2020/11/09 【Unity】【C#】非アクティブも含めて、Transform (GameObject) をパス名で取得する
- 2020/11/08 【Unity】【C#】Transfrom (GameObject) のパス名を取得する
- 2020/11/07 【Unity】【C#】非アクティブも含めて、全ての GameObject からコンポーネントを取得する
« prev next »
【Unity】【エディタ拡張】ヒエラルキー(シーン)の Image, RawImage に使われている画像(Texture)を検出するエディタ拡張(ツール) 
2020/11/11 Wed [edit]
1つのアプリの開発を長く続けていると「あれ?この画像もう使ってなかったような…?」なんてこと良くある。バージョンアップによって不要になった画像や、アイコン(UI)を変更したり、プロジェクト内には残ってるけど、実際のシーン(ヒエラルキー)上には使ってなかったり。だけど、いきなり削除してしまうと、万が一使ってるものがあったら、画像が抜けてしまう…。
そんなときに利用するツール。プロジェクトビューからツールに画像を指定して、検索ボタン(Search)を押せば、今開いているシーンの全ての Image, RawImage にセットされている画像と比較して、検出してくれる。
検索結果をクリックすれば、オブジェクトを選択してくれるし、検出後に [Select] ボタンを押せば、全てを選択してくれるので、画像を一気に入れ替えるなども簡単だ。
ここではツールのマニュアル的なものを書いておこう。
(※) Unity 2019.4.14f1 / Windows10(x64) で確認
■AttachedImageFinder のインポートと起動
パッケージのインポートダイアログでは、ツール本体(スクリプト)とテスト用のシーンが入っている。「_Test」以下はテスト用のサンプルシーンなので、ツールだけで良いなら、スクリプトだけでも良い。

ツール(スクリプト)をインポートしたら、「Tools」メニュー以下に「Attached Image Finder」が追加されるので、そこから起動しよう。

■AttachedImageFinder の使い方
「Tools」メニューから起動したら、「検索画像(Texture)」に画像をセットしよう。プロジェクトビューからドロップしても良いし、ボックスの一番右にある◎を押して、画像を選択しても良い。

デフォルトでは(None のとき)ヒエラルキーの全てのオブジェクトから検索するが、範囲を絞り込みたいときは、検索開始となる Transform をヒエラルキーからドロップしてセットしよう。セットした場合はその位置以下の階層からしか検出しなくなる。
「検索オプション」の Image, RawImage はチェックを付けたものにセットされている画像から検出する。


検索後は結果をクリックするか、「Select」ボタンを押せば、結果全てを選択できる。

ちなみに、ヒエラルキーの階層を一気に展開するには、親を選択した後で、[Alt] + [→] (開く), [Alt] + [←] (閉じる) のショートカットを使うと便利だ。
あとは画像を入れ替えたり、削除したりと自分の好きにすれば良い。
使い方は難しくないだろう。
AttachedImageFinder はスクリプトだけでできているので、自由にコピペして新しいツールでも作ってみるのも良いだろう。そのほとんどの機能が前回までの Transform 系の便利メソッドで作られている。誰かの役に立つのであれば、公開した甲斐があるというものである(笑)。
(関連記事)
【Unity】【C#】シーン(ヒエラルキー)のルートにある Transform を全て取得する(非アクティブも含む)
【Unity】【C#】非アクティブも含めて、全ての GameObject からコンポーネントを取得する
【Unity】【C#】Transfrom (GameObject) のパス名を取得する
【Unity】【C#】非アクティブも含めて、Transform (GameObject) をパス名で取得する
【Unity】【C#】ヒエラルキー(シーン)の全てのオブジェクト(Transform)をスキャンして処理をする
【Unity】【C#】EventSystem を InputSystem 用に置き換えると、スクロールビュー等の移動が速過ぎる
- 関連記事
category: Unity
thread: ゲーム開発
janre: コンピュータ
tag: Unityライブラリ Unityプラグイン エディタ拡張 Transform FantomPlugin【Unity】【C#】ヒエラルキー(シーン)の全てのオブジェクト(Transform)をスキャンして処理をする 
2020/11/10 Tue [edit]
どちらかというとエディタ拡張(ツール)用。まぁ、使い方によってはランタイムでも良い。
前回の FindTransformByPath() では再帰ルーチンを用いてヒエラルキーを探索していたが、それを取り出して汎用的にしたものと考えても良い(というより、FindTransformByPath() の方が、パス検索用に最適化したものと言える)。
内容的には深さ優先探索で、全ての Transform を無条件に走査するので、負荷はそれなりに高い(アクティブ・非アクティブに関係無く、全てを対象とするため、ヒエラルキー上のオブジェクトの数に比例して時間がかかる)。だが、開発用のツールを自作するときなどは、かなり便利だと思うので、好きに使って欲しい。
(※) Unity 2019.4.14f1 / Windows10(x64) で確認
●深さ優先探索で現在のシーンの全ての Transform を走査(非アクティブ, ""(空の名前) も含む)
using UnityEngine;
/// <summary>
/// 深さ優先探索で現在のシーンの全ての Transform を走査(非アクティブ, ""(空の名前) も含む).
/// 2020/11/10 Fantom (Unity 2019.4)
/// http://fantom1x.blog130.fc2.com/blog-entry-381.html
/// ・再帰での全探索のため、負荷が高く遅いので、ランタイム時の使用は注意.
/// ・コールバックのパス名(path)の頭に '/' は付かない.
/// ・コールバックの階層(rank)はルート or 開始Transform 自身が 0 であり、1つ下階層から 1, 2, 3,… n となる.
/// </summary>
/// <param name="transform">検出開始の Transform (null のとき全て)</param>
/// <param name="callback">Transform, パス名, 階層(ルート,開始は0) のコールバック</param>
/// <param name="maxRank">検索する最大階層: n階層下まで対象 (-1 のとき全ての階層)</param>
public static void DepthFirstScan(this Transform transform, Action<Transform, string, int> callback, int maxRank = -1)
{
if (transform != null)
{
ScanRecursive(transform, callback, "", 0, maxRank);
}
else
{
var roots = GetRootTransforms(); //ルートにある Transform 全て取得(非アクティブも含む)※以前の記事を参照
//全てのルート Transform 以下に再帰で走査する
foreach (var tr in roots)
{
ScanRecursive(tr, callback, "", 0, maxRank);
}
}
}
//再帰処理用
/// <summary>
/// 指定 Transform から、深さ優先探索で Transform を走査する(非アクティブ, ""(空の名前) も含む).
/// 2020/11/10 Fantom (Unity 2019.4)
/// http://fantom1x.blog130.fc2.com/blog-entry-381.html
/// ・同じパス名が複数ある場合もあるので注意(自由に付けられる名前のため).
/// ・パス名は "/" 区切りで表すので、名前に "/" が入っている場合は上手く検出できない(曖昧になる).
/// ・コールバックのパス名(path)の頭に '/' は付かない.
/// ・コールバックの階層(rank)はルート or 開始Transform 自身が 0 であり、1つ下階層から 1, 2, 3,… n となる.
/// ・Transform.Find() に近い結果になるが、最後が '/' の場合、配下の ""(空の名前)として検索する.
/// </summary>
/// <param name="transform">検出開始の Transform</param>
/// <param name="callback">Transform, パス名, 階層(ルートは0) のコールバック</param>
/// <param name="currentPath">再帰での現在のパス名</param>
/// <param name="rank">再帰での現在の階層 (0 がルート,開始)</param>
/// <param name="maxRank">検索する最大階層: n階層下まで対象 (-1 のとき全ての階層)</param>
/// <returns></returns>
private static Transform ScanRecursive(Transform transform, Action<Transform, string, int> callback, string currentPath, int rank, int maxRank = -1)
{
if (transform == null || (maxRank > -1 && rank > maxRank))
return null;
if (string.IsNullOrEmpty(currentPath))
currentPath = transform.name;
if (callback != null)
callback.Invoke(transform, currentPath, rank);
if (transform.childCount == 0)
return null;
for (int i = 0; i < transform.childCount; i++)
{
var child = transform.GetChild(i);
var childPath = currentPath + "/" + child.name; //""(空の名前) でもヒットできる
Transform tr = ScanRecursive(child, callback, childPath, rank + 1, maxRank);
if (tr != null)
return tr;
}
return null;
}
●使用例(メインコード等)
using UnityEngine;
int count = 0;
DepthFirstScan(
null,
(tr, path, rank) =>
{
count++;
Debug.Log($"{tr.name} : path = {path}, rank = {rank}");
});
Debug.Log($"Count = {count}");

GetRootTransforms() は以前の記事からコピペして欲しい。テストも前回のサンプルとほぼ同様なもので試してみよう。
内容的にはただ全てのオブジェクトを走査するだけで、何もしないので、自分の処理を挟むには Action<Transform, string, int> の引数を与える必要がある。コールバックハンドラ(delegate)を作成、または例のように匿名メソッドで書いても良いだろう。
コールバックの第一引数の Transform が現在走査しているオブジェクトなので、プロパティやメソッドを使えば色々できる。GameObject が欲しいなら .gameObject プロパティを使えば良い。ただ、一定のコンポーネントを取得するだけの処理なら、以前に作った GetComponentsAll() を使った方が速いし簡単。複雑な条件分岐を挟むには DepthFirstScan() の方が書きやすいかも知れない。
また、パス名は空白の名前でも利用できるようになっているため、頭に '/' は付けないパス名となっている。頭に '/' を付けたときは親が ""(空の名前)で子が名前として認識する。また GameObject.Find() では最後の '/' の有無は関係ないが、このメソッドの場合、最後のオブジェクトが ""(空の名前) になる。
コメントにも書いておいたが、引数の rank は検索開始の階層(自身の階層)を 0 とし、下の階層を 1, 2, 3,… で表しているので、テストのように "E/F" の名前が付いているものと、E が親で F が子の関係になっているオブジェクトでも、rank を見れば、区別は付けられる(ただし、名前自体に '/' が入っていると、GameObject.Find などでも上手く検出できなくなるので、なるべく避けた方が良い)。
ScanRecursive() は再帰処理用なので private にしてある。DepthFirstScan() の第一引数が null ならヒエラルキーのルートから、null 以外なら指定 Transform から検索開始するので、public にする必要は無いだろう。
これらメソッドは再帰処理してるので、ランタイムでの利用する場合は、開始 Transform を指定したり、階層制限(maxRank) を指定して、検索範囲を絞った方が良い。走査するオブジェクト数が多くなるほど処理時間がかかるので、注意しよう。
(関連記事)
【Unity】【C#】シーン(ヒエラルキー)のルートにある Transform を全て取得する(非アクティブも含む)
【Unity】【C#】非アクティブも含めて、全ての GameObject からコンポーネントを取得する
【Unity】【C#】非アクティブも含めて、Transform (GameObject) をパス名で取得する
【Unity】【C#】Transfrom (GameObject) のパス名を取得する
- 関連記事
-
-
【Unity】標準以外のセンサー(歩数計や心拍数など)を使う(Android)
-
【Unity】【C#】非アクティブも含めて、Transform (GameObject) をパス名で取得する
-
【Unity】【C#】Unity4 Free版で RenderTexture のようなオフスクリーンレンダリングをして、ユニティちゃんステージのバックスクリーンを作る
-
【Unity】エディタ上(Visual Studio等)のスクリプトをUTF8に固定する
-
【Unity】UI のフォーカスを外すコードと「Attempting to select while already selecting an object.」
-
category: Unity
thread: ゲーム開発
janre: コンピュータ
tag: Unityライブラリ Unityリファレンス Transform【Unity】【C#】非アクティブも含めて、Transform (GameObject) をパス名で取得する 
2020/11/09 Mon [edit]
今回もこれまでの Transform 系の便利メソッド応用。
前回、GameObject.Find でのパス名の使い方を解説したが、このメソッドは非アクティブなオブジェクトにはヒットしないという欠点がある。
なので、非アクティブなオブジェクトを取得したいときは、Resources.FindObjectsOfTypeAll() をゴニョゴニョする、みたいな例が多いね。
それでもいいけど、これまでの応用でも検出はできるので、せっかくなので簡単な再帰ルーチンを用いて、パスで Transform (GameObject) を検索するメソッドを作ってみよう。
今回のメソッドでは Transform を返しているが、GameObject が欲しいなら、戻値から transform.gameObject を取得すれば良い。
(※) Unity 2019.4.14f1 / Windows10(x64) で確認
●ルートからのパス名(絶対パス)を指定して Transform を検出する(非アクティブ, ""(空の名前) も含む)
using UnityEngine;
/// <summary>
/// ルートからのパス名(絶対パス)を指定して Transform を検出する(非アクティブ, ""(空の名前) も含む).
/// 2020/11/09 Fantom (Unity 2019.4)
/// http://fantom1x.blog130.fc2.com/blog-entry-380.html
/// ・同じパス名が複数ある場合、一番最初に見つけたものになる.
/// ・パス名は "/" 区切りで表すので、名前に "/" が入っている場合は上手く検出できない(曖昧になる).
/// ・"nameA/nameB/" → ""(空の名前の Transform) がヒットする(ヒットしないようにするには、最後の '/' を取り除いておく)
/// ・"/name" ではルートが ""(空の名前) で配下が "name" の検出となる.
/// ・GameObject.Find() のようにルート以下のパス名にはヒットできない(絶対パスのみ).
/// ・検索するオブジェクトがアクティブ前提なら、GameObject.Find() の方が速い.
/// ・再帰での全探索のため、負荷が高く遅いので、ランタイム時の使用は注意.
/// ・検索範囲は、現在のシーン:SceneManager.GetActiveScene() 内のみ(GetRootTransforms() に依存).
/// </summary>
/// <param name="path">絶対パス指定: "nameA/nameB" (頭に '/' は付けない)</param>
/// <returns>見つかった Transform / 見つからなかったときは null</returns>
public static Transform FindTransformByPath(string path)
{
if (path == null) //"" (空の名前) は可
return null;
//ルートとそれ以下に分ける
string rootName = path;
string relativePath = null; //null はルートのみのときのフラグとなっている
int idx = path.IndexOf('/');
if (idx >= 0)
{
rootName = path.Substring(0, idx);
relativePath = path.Substring(idx + 1);
}
var roots = GetRootTransforms(); //ルートにある Transform 全て取得(非アクティブも含む)※以前の記事を参照
//全てのルート Transform 以下に再帰で path を検出する
foreach (var tr in roots)
{
if (tr.name == rootName)
{
if (relativePath == null) //ルートのみのとき
return tr;
var result = FindRecursive(tr, path, "");
if (result != null)
return result;
}
}
return null;
}
//再帰処理用
/// <summary>
/// 指定 Transform から、深さ優先探索で Transform を検出する(非アクティブ, ""(空の名前) も含む).
/// 2020/11/09 Fantom (Unity 2019.4)
/// http://fantom1x.blog130.fc2.com/blog-entry-380.html
/// ・同じパス名が複数ある場合、一番最初に見つけたものになる.
/// ・パス名は "/" 区切りで表すので、名前に "/" が入っている場合は上手く検出できない(曖昧になる).
/// ・Transform.Find() に近い結果になるが、最後が '/' の場合、配下の ""(空の名前) として検出する.
/// ・また、Transform.Find() と違い、自身を含める検出となる.
/// (例) "nameA/nameB/nameC" を検出したいとき、transform = nameA, path = "nameA/nameB/nameC" を引数に与える.
/// </summary>
/// <param name="transform">検出開始の Transform</param>
/// <param name="targetPath">検索するパス名</param>
/// <param name="currentPath">再帰での現在のパス名</param>
/// <returns>見つかった Transform / 見つからなかったときは null</returns>
private static Transform FindRecursive(Transform transform, string targetPath, string currentPath)
{
if (transform == null || targetPath == null)
return null;
if (string.IsNullOrEmpty(currentPath))
currentPath = transform.name;
if (targetPath == currentPath)
return transform;
if (transform.childCount == 0 || !targetPath.StartsWith(currentPath))
return null;
for (int i = 0; i < transform.childCount; i++)
{
var child = transform.GetChild(i);
var childPath = currentPath + "/" + child.name; //""(空の名前) でもヒットできる
Transform tr = FindRecursive(child, targetPath, childPath);
if (tr != null)
return tr;
}
return null;
}
●使用例(メインコード等)
using System.Linq;
using UnityEngine;
var transforms = GetComponentsAll<Transform>(); //※以前の記事を参照
foreach (var tr in transforms)
{
var path = tr.GetFullPathName(); //※以前の記事を参照
var go = FindTransformByPath(path).gameObject;
Debug.Log($"{go.name} : path = {path}");
}

GetRootTransforms(), GetComponentsAll(), GetFullPathName() の3つのメソッドは以前の記事からコピペして欲しい。テストは前回のサンプルとほぼ同様なもので試してみよう。内容的には、全ての Transform を取得 → パス名を取得 → パス名で Transform.gameObject を取得ということをやっている。
ただ、GameObject.Find() のパス名の書き方とは少し違う点を気をつけて欲しい。なるべくコメントにも書いておいたが、今回のメソッドは絶対パス指定のみとなっているため、途中階層にあるパスのパターンにはヒットしない。
また、空白の名前でもヒットするようになっているため、頭に '/' は付けないパス名となっている。頭に '/' を付けたときは親が ""(空の名前)で子が名前として認識する。また GameObject.Find() では最後の '/' の有無は関係ないが、今回のメソッドの場合、最後のオブジェクトが ""(空の名前) でヒットする。
もちろん、名前自体に '/' が入っていると上手く検出できない("A/B" は1つの名前とも階層とも取れるので曖昧となる。※これは GameObject.Find でも同じ)。
FindRecursive() は再帰処理用なので private にしてあるが、普段も利用したければ、
public static Transform FindRecursive(this Transform transform, string targetPath)
{
return FindRecursive(transform, targetPath, "");
}
みたいに public なオーバーロードを定義しても良いだろう。この場合、指定した Transform 以下を検索することになる。Transform.Find() に近い感じになるが、自分自身を起点に検索範囲に含まれる点が違う。
これらメソッドも再帰処理してるので、ランタイムでの利用はほどほどにした方が良いだろう。エディタツールなどで使う分には、ほとんど問題ないパフォーマンスが出る。
通常、決まったオブジェクトを検索したいのなら、GameObject.FindWithTag() を使った方がパフォーマンスが良い。ただし、事前にタグを作成(設定)しておく必要がある。
ヒエラルキーでユニークな名前のオブジェクトなら、使いやすいかも知れない。
(関連記事)
【Unity】【C#】シーン(ヒエラルキー)のルートにある Transform を全て取得する(非アクティブも含む)
【Unity】【C#】非アクティブも含めて、全ての GameObject からコンポーネントを取得する
【Unity】【C#】ヒエラルキー(シーン)の全てのオブジェクト(Transform)をスキャンして処理をする
【Unity】【C#】Transfrom (GameObject) のパス名を取得する
【Unity】【C#】Transfrom (GameObject) のパス名を取得する 
2020/11/08 Sun [edit]
前回に引き続き、少しばかり Transform (GameObject) の便利メソッドを書いておく。
GameObject.Find のマニュアルを見るとわかるが、ヒエラルキーの各オブジェクトの名前を '/' (スラッシュ) で繋げて、特定のオブジェクトを階層で指定することができる(ただし、ファイルシステムとは違い、名前は自由に付けられるため、同名パスが複数存在する場合があることに注意)。
これに近いものを作るメソッドを定義してみよう。このメソッドでは Transform を返しているが、GameObject が欲しいなら、戻値から transform.gameObject を取得すれば良い。
(※) Unity 2019.4.14f1 / Windows10(x64) で確認
●Transform の(フル)パス名を作成する
using UnityEngine;
/// <summary>
/// Transform の(フル)パス名を作成する
/// 2020/11/08 Fantom (Unity 2019.4)
/// http://fantom1x.blog130.fc2.com/blog-entry-379.html
/// </summary>
/// <param name="transform">パス名を取得する Transform</param>
/// <returns>ヒエラルキールートからのパス名 (頭に '/' は付かない)</returns>
public static string GetFullPathName(this Transform transform)
{
if (transform.parent == null)
return transform.name;
return GetFullPathName(transform.parent) + "/" + transform.name;
}
●使用例(メインコード等)
using System.Linq;
using UnityEngine;
var transforms = GetComponentsAll<Transform>(); //※前回の記事を参照
foreach (var tr in transforms)
{
Debug.Log(tr.GetFullPathName());
}

GetRootTransforms(), GetComponentsAll() の2つのメソッドは以前の記事からコピペして欲しい。テストは前回のサンプルとほぼ同様なもので試してみよう。パス名となっているので、階層での位置がよくわかる。
ただ、戻値には頭に '/' は付かないので、GameObject.Find() で絶対パスのように使うときには、頭に '/' を追加する必要がある(※また、GameObject.Find() はアクティブなオブジェクトしか検出しないので注意)。
ちなみに、頭に '/' があるとき:"/nameA/nameB/nameC" はルート直下からとなり、
無いとき:"nameA/nameB/nameC" はルート以外でもパターンが合えば、どの階層でもヒットするようだ(複数ある場合、一番最初に見つかったのものとなる。深さ優先探索っぽい)。
また、似たようなものに、Transform.Find() というものもあるが、これは自身を除いた、子Transform 内で検出される。
このメソッドは再帰処理なので、ランタイムでの利用はほどほどにした方が良いね。
通常、決まったオブジェクトを検索したいのなら、GameObject.FindWithTag() を使った方がパフォーマンスが良い。ただし、事前にタグを作成(設定)しておく必要がある。
ヒエラルキーでユニークな名前のオブジェクトなら、使いやすいかも知れない。
(関連記事)
【Unity】【C#】シーン(ヒエラルキー)のルートにある Transform を全て取得する(非アクティブも含む)
【Unity】【C#】非アクティブも含めて、全ての GameObject からコンポーネントを取得する
【Unity】【C#】非アクティブも含めて、Transform (GameObject) をパス名で取得する
【Unity】【C#】ヒエラルキー(シーン)の全てのオブジェクト(Transform)をスキャンして処理をする
- 関連記事
-
-
【Unity】IncrementalCompiler でのエラー:Unloading broken assembly Packages/com.unity.incrementalcompiler/Editor/Plugins/Unity.PureCSharpTests.dll, this assembly can cause crashes in the runtime
-
【Unity】Androidのテキスト読み上げ(TextToSpeech)を使う
-
【Unity】Unity2020 でプラットフォーム切り替えをすると、Run In Background が勝手にオフになってしまう
-
【Unity】5.6 の Collider2Dは非アクティブ化で On~Exit2D イベントが発生する(5.6のコライダ2D挙動の違い)
-
【Unity】【C#】床面(Yaw)/YZ平面(Pitch)に射影された角度を、符号(方向)付きで求める [3D]
-
category: Unity
thread: ゲーム開発
janre: コンピュータ
tag: Unityライブラリ Unityリファレンス Transform【Unity】【C#】非アクティブも含めて、全ての GameObject からコンポーネントを取得する 
2020/11/07 Sat [edit]
前回の「シーン(ヒエラルキー)のルートにある Transform を全て取得する」の応用。ググってみたら、意外と色々面倒なことをやってる例が多かったので、シンプルなものがあっても良いかなと(笑)。
シーン全体からコンポーネントを取得するには Object.FindObjectsOfType() をよく使うけど、これってアクティブな GameObject からのみなんだよね。
非アクティブも含むなら、Resources.FindObjectsOfTypeAll() を使え、ともあるけど、このメソッドはエディタ上で使うと、プレファブからも取得してしまうので、フィルタをかける必要があり、少しコードが面倒くさくなる。
なので、あくまで現在のシーンからアクティブ・非アクティブに関わらず、簡単にコンポーネントを取得する静的メソッドを作っておくと便利だと思った。
もっと細かい条件付けで取得したいときは、以下に資料を載せておくので、各記事を参考にして欲しい。
(参考)
・【Unity】Hierarchy に存在するすべてのゲームオブジェクトを取得する方法
・【Unity】Hierarchy上のゲームオブジェクトを全て取得
・Hierarchy上のゲームオブジェクトを全て取得したい!
(※) Unity 2019.4.14f1 / Windows10(x64) で確認
●現在のシーン(ヒエラルキー)の全てのオブジェクトからコンポーネントを取得する(非アクティブも含む)
using System.Collections.Generic;
/// <summary>
/// 現在のシーン(ヒエラルキー)の全てのオブジェクトからコンポーネントを取得する(非アクティブも含む)
/// 2020/11/07 Fantom (Unity 2019.4)
/// http://fantom1x.blog130.fc2.com/blog-entry-378.html
/// </summary>
/// <typeparam name="T">取得するコンポーネントの型</typeparam>
/// <returns>取得した T の配列(無いときは、0 個の配列)</returns>
public static T[] GetComponentsAll<T>()
{
var list = new List<T>();
var roots = GetRootTransforms(); //ルートにある Transform 全て取得(非アクティブも含む)※前回の記事参照
//全てのルート Transform 以下に GetComponentsInChildren() する
foreach (var tr in roots)
{
var objects = tr.GetComponentsInChildren<T>(true); //非アクティブも含む取得
if (objects != null && objects.Length > 0)
{
list.AddRange(objects);
}
}
return list.ToArray(); //無いときは、0 個の配列(null にはならない)
}
●使用例(メインコード等)
using System.Linq;
using UnityEngine;
var transforms = GetComponentsAll<Transform>();
foreach (var tr in transforms)
{
Debug.Log(tr.name);
}
//GameObject にしたい場合は、LINQ を使うと簡単
var objects = transforms.Select(e => e.gameObject).ToArray();

GetRootTransforms() は前回の記事からコピペして欲しい。GetRootTransforms() では、SceneManager.GetActiveScene() で現在のシーンからのみ取得してるので、対象外のシーンからは取得できないので注意。
また利用の際は、GetComponentsInChildren() をルートにある Transform の数だけ繰り返すので、負荷には注意。ランタイム時には濫発しない方が良いだろう。エディタ上でなら思ったより速かったので、問題なく使えると思う。
(関連記事)
【Unity】【C#】シーン(ヒエラルキー)のルートにある Transform を全て取得する(非アクティブも含む)
【Unity】【C#】Transfrom (GameObject) のパス名を取得する
【Unity】【C#】非アクティブも含めて、Transform (GameObject) をパス名で取得する
【Unity】【C#】ヒエラルキー(シーン)の全てのオブジェクト(Transform)をスキャンして処理をする