I am collapsing a selected parent gameObject with this editor script. It all works well but it also collapses other expanded gameObjects which should not happen. For example under two different parents, if I collapse one parent gameObject, even the other parent gameObject gets collapsed. How do I not let this happen?
I feel the problem is at rootGameObjects.AddRange (SceneManager.GetSceneAt (i).GetRootGameObjects ()); where it takes the root gameObject in a scene but not the selected gameObject in the hierarchy.
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
public static class CollapseTools {
private static int wait = 0;
private static int undoIndex;
public static void CollapseGameObjects () {
EditorApplication.update -= CollapseGameObjects;
CollapseGameObjects (new MenuCommand (null));
}
[MenuItem ("GameObject/Collapse GameObjects", priority = 40)]
private static void CollapseGameObjects (MenuCommand command) {
// This happens when this button is clicked via hierarchy's right click context menu
// and is called once for each object in the selection. We don't want that, we want
// the function to be called only once
if (command.context) {
EditorApplication.update -= CollapseGameObjects;
EditorApplication.update += CollapseGameObjects;
return;
}
List<GameObject> rootGameObjects = new List<GameObject> ();
#if UNITY_2018_3_OR_NEWER
// Check if a prefab stage is currently open
var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage ();
if (prefabStage != null && prefabStage.stageHandle.IsValid ())
rootGameObjects.Add (prefabStage.prefabContentsRoot);
else
#endif
{
int sceneCount = SceneManager.sceneCount;
for (int i = 0; i < sceneCount; i++)
rootGameObjects.AddRange (SceneManager.GetSceneAt (i).GetRootGameObjects ());
}
if (rootGameObjects.Count > 0) {
Undo.IncrementCurrentGroup ();
Selection.objects = Selection.objects;
undoIndex = Undo.GetCurrentGroup ();
Selection.objects = rootGameObjects.ToArray ();
EditorApplication.update -= CollapseHelper;
EditorApplication.update += CollapseHelper;
}
}
private static void CollapseHelper () {
if (wait < 1) // Increase the number if script doesn't always work
wait++;
else {
EditorApplication.update -= CollapseHelper;
wait = 0;
EditorWindow focusedWindow = EditorWindow.focusedWindow;
if (focusedWindow != null)
focusedWindow.SendEvent (new Event { keyCode = KeyCode.LeftArrow, type = EventType.KeyDown, alt = true });
Undo.RevertAllDownToGroup (undoIndex);
}
}
}
When it comes to Unity, nothing beats reflection:
using UnityEditor;
using UnityEngine;
internal class MyClass : EditorWindow
{
private void OnGUI()
{
using (var scope = new EditorGUI.DisabledGroupScope(Selection.activeGameObject == null))
{
if (GUILayout.Button("Expand Recursive"))
{
var type = typeof(EditorWindow).Assembly.GetType("UnityEditor.SceneHierarchyWindow");
var window = GetWindow(type);
var exprec = type.GetMethod("SetExpandedRecursive");
exprec!.Invoke(window, new object[] {Selection.activeGameObject.GetInstanceID(), true});
}
}
}
[MenuItem("TEST/TEST")]
private static void Init()
{
GetWindow<MyClass>();
}
}
Check SceneHierarchyWindow class for other things you could hook into.
Now you have another problem, when you have multiple hierarchy windows open, I'll let you solve that one :)