はじめに
今回はSelection Groupsについて取り上げたいと思います。
Selection GroupはUnity公式パッケージで、複数のGameObjectをグループ化・操作することができます。
Selection Group は、Unity のワークフローをより快適にします。 複数の GameObject を共通の名前でグループ化して、グループ単位で操作を行うことができます。
またGoQLという条件を満たすGameObjectを抽出する機能は非常に便利なので是非習得してみるとよいと思います。

GoQL は「GameObject Query Language」の略です。 シーンのヒエラルキーから GameObject のセットを構築するために使用されます。
この API は単一のクエリ文字列をパラメーターとして受け取り、そのクエリにマッチする GameObject のセットを返します。
GoQL オーバービュー | Selection Groups | 0.9.1-preview
ただ現段階(2023/4/9時)ではExperimentalパッケージで中身が変更される可能性もあります。注意してください。
インストール方法
メニューバーのWindow -> PackageManagerからPackage Managerを立ち上げ、Add package from git URLにて以下の文字列を入力し、Addボタンを押せばインストールできます。
com.unity.selection-groups

使い方
Selection Groups Windowの立ち上げ方法
メニューバーのWindow -> General -> Selection Groupsを選択し、Selection Groups Windowを立ち上げます。

Selection Groupの作成
Selection Groups Windowの+ボタンを押し、Create Empty Groupを選択すると、HierarchyにSelectionGroupコンポーネントがアタッチされたGameObjectが生成されます。


Selection GroupにGameObjectを追加する
Hierarchyから対象のGameObjectをSelection Groupsの対象Selection Groupへとドラッグ&ドロップします。

このときSelection GroupコンポーネントがアタッチされているGameObjectと階層構造になるわけではないということに注意してください。
Selection Groupコンポーネント

| プロパティ | 説明 |
|---|---|
| Group name | GameObject グループの名前と同じです。 |
| Color | Selection Groups Window に表示されているグループのカラーです。 |
| Group Query | クエリを指定すると、そのクエリに合致する階層の GameObject を自動的にグループに割り当てます。詳しくは、GoQL のドキュメントを参照してください。 |
Group name
まずGroup nameを変更すると、GameObjectの名前も連動して変更されます。

Color
Colorに関してはSelection Groups Windowに表示されるグループカラーを変更することができます。

Group Query
Group QueryはSelection Groupsの一番特筆すべき機能といってもよいでしょう。
Group QueryはGoQL(GameObject Query Language)という、イメージSQLのGameObject版のような問い合わせ言語を用いて、条件に合ったGameObjectを自動的にグループに割り当てることができます。
クエリを指定すると、そのクエリに合致する階層の GameObject を自動的にグループに割り当てます。
例えば*ManagerとGroup Queryに記載すると、GameManagerのようにManagerで終わるGameObjectをグループに割り当てることができます。

グループに対して何かしらの操作をする
Hierarchy上
グループ内のGameObjectをHierarchy上ですべて選択したい場合は、グループをダブルクリックするか、グループ上で右クリックしてSelect All Group Membersを選択します。

スクリプト上
コード上では、SelectionGroupコンポーネントに対して以下のコードを書くことでアクセスすることができます。
public class Test : MonoBehaviour { [SerializeField] private SelectionGroup selectionGroup; private void Start() { // グループ内のゲームオブジェクトを取得する IList<GameObject> gameObjects = selectionGroup.Members; // 非アクティブにする foreach (var item in gameObjects) { item.SetActive(false); } } }
補足
インストールするとPackages/Selection Groupsにパッケージが入るわけですが、そこまで規模の大きなものではないので割と読みやすく参考になったりします。
フォルダ構成とか、Testの書き方、AssemblyInfo.csとか結構参考になります。
というかチラッと眺めていたら気づいたのですが、Unity公式のパッケージなのにハンガリアン記法使っていないのですね。
// MonoBehavior.cs namespace UnityEngine { /// <summary> /// <para>MonoBehaviour is a base class that many Unity scripts derive from.</para> /// </summary> [NativeHeader("Runtime/Mono/MonoBehaviour.h")] [NativeHeader("Runtime/Scripting/DelayedCallUtility.h")] [RequiredByNativeCode] [ExtensionOfNativeClass] public class MonoBehaviour : Behaviour { private CancellationTokenSource m_CancellationTokenSource; // 以下省略
// SelectionGroups内のコード namespace Unity.SelectionGroups { /// <summary> /// A HashSet which retains order of items as they are added or inserted. /// or /// A List which only contains unique references. /// </summary> /// <typeparam name="T"></typeparam> internal class OrderedSet<T> : IList<T> { List<T> items = new List<T>(); HashSet<T> uniqueIndex = new HashSet<T>(); public IList<T> List => items; public T this[int index] { get => items[index]; set => items[index] = value; } public int Count => items.Count; public bool IsReadOnly => false; public void Add(T item) { if(!uniqueIndex.Contains(item)) { items.Add(item); uniqueIndex.Add(item); } } public void Clear() { items.Clear(); uniqueIndex.Clear(); } public bool Contains(T item) { return uniqueIndex.Contains(item); } public void CopyTo(T[] array, int arrayIndex) { items.CopyTo(array, arrayIndex); } public IEnumerator<T> GetEnumerator() { return items.GetEnumerator(); } public int IndexOf(T item) { return items.IndexOf(item); } public void AddRange(IEnumerable<T> objectReferences) { foreach (var i in objectReferences) { Add(i); } } public void Insert(int index, T item) { if(!uniqueIndex.Contains(item)) { items.Insert(index, item); uniqueIndex.Add(item); } } public bool Remove(T item) { uniqueIndex.Remove(item); return items.Remove(item); } public void Remove(IList<T> items) { uniqueIndex.ExceptWith(items); foreach(var i in items) { this.items.Remove(i); } } public void RemoveAt(int index) { var item = items[index]; uniqueIndex.Remove(item); items.RemoveAt(index); } IEnumerator IEnumerable.GetEnumerator() { return items.GetEnumerator(); } } }
昔の名残なのか何でこんな変数名つけてんだろうなとか思っていた(もしかしたらC++のエンジン側の影響??)のですが、パッケージの中身は割とMicrosoftの規約に従っていそうな雰囲気を感じました。
ちょっと面白かったので補足として掲載しておきます。