This little snippet allows you to see which objects you are hovering over in the Unity3D hierarchy pane. It also shows which objects are being dragged.
Here's the script. You will need to place this script into your Assets directory, inside the 'Editor' folder. If the 'Editor' folder does not exist, you need to create it.
using System; | |
using System.Collections.Generic; | |
using System.Reflection; | |
using UnityEditor; | |
using UnityEngine; | |
[InitializeOnLoad] | |
public class HighlightHelper { | |
private static readonly Type HierarchyWindowType; | |
static HighlightHelper() { | |
EditorApplication.hierarchyWindowItemOnGUI += HierarchyWindowItemOnGUI; | |
EditorApplication.update += EditorUpdate; | |
SceneView.onSceneGUIDelegate += OnSceneGUIDelegate; | |
Assembly editorAssembly = typeof (EditorWindow).Assembly; | |
HierarchyWindowType = editorAssembly.GetType("UnityEditor.SceneHierarchyWindow"); | |
} | |
private static void EditorUpdate() { | |
var currentWindow = EditorWindow.mouseOverWindow; | |
if (currentWindow && currentWindow.GetType() == HierarchyWindowType) { | |
if (!currentWindow.wantsMouseMove) { | |
//allow the hierarchy window to use mouse move events! | |
currentWindow.wantsMouseMove = true; | |
} | |
} else { | |
_hoveredInstance = 0; | |
} | |
} | |
private static readonly Color HoverColor = new Color(1, 1, 1, 0.75f); | |
private static readonly Color DragColor = new Color(1f, 0, 0, 0.75f); | |
private static void OnSceneGUIDelegate(SceneView sceneView) { | |
switch (Event.current.type) { | |
case EventType.DragUpdated: | |
case EventType.DragPerform: | |
case EventType.DragExited: | |
sceneView.Repaint(); | |
break; | |
} | |
if (Event.current.type == EventType.repaint) { | |
var drawnInstanceIDs = new HashSet<int>(); | |
Color handleColor = Handles.color; | |
Handles.color = DragColor; | |
foreach (var objectReference in DragAndDrop.objectReferences) { | |
var gameObject = objectReference as GameObject; | |
if (gameObject && gameObject.activeInHierarchy) { | |
DrawObjectBounds(gameObject); | |
drawnInstanceIDs.Add(gameObject.GetInstanceID()); | |
} | |
} | |
Handles.color = HoverColor; | |
if (_hoveredInstance != 0 && !drawnInstanceIDs.Contains(_hoveredInstance)) { | |
GameObject sceneGameObject = EditorUtility.InstanceIDToObject(_hoveredInstance) as GameObject; | |
if (sceneGameObject) { | |
DrawObjectBounds(sceneGameObject); | |
} | |
} | |
Handles.color = handleColor; | |
} | |
} | |
private static void DrawObjectBounds(GameObject sceneGameObject) { | |
var bounds = new Bounds(sceneGameObject.transform.position, Vector3.one); | |
foreach (var renderer in sceneGameObject.GetComponents<Renderer>()) { | |
Bounds rendererBounds = renderer.bounds; | |
rendererBounds.center = sceneGameObject.transform.position; | |
bounds.Encapsulate(renderer.bounds); | |
} | |
float onePixelOffset = HandleUtility.GetHandleSize(bounds.center)*1/64f; | |
float circleSize = bounds.size.magnitude*0.5f; | |
Handles.CircleCap(0, bounds.center, | |
sceneGameObject.transform.rotation, circleSize - onePixelOffset); | |
Handles.CircleCap(0, bounds.center, | |
sceneGameObject.transform.rotation, circleSize + onePixelOffset); | |
Handles.CircleCap(0, bounds.center, sceneGameObject.transform.rotation, circleSize); | |
} | |
private static int _hoveredInstance; | |
private static void HierarchyWindowItemOnGUI(int instanceID, Rect selectionRect) { | |
var current = Event.current; | |
switch (current.type) { | |
case EventType.mouseMove: | |
if (selectionRect.Contains(current.mousePosition)) { | |
if (_hoveredInstance != instanceID) { | |
_hoveredInstance = instanceID; | |
if (SceneView.lastActiveSceneView) { | |
SceneView.lastActiveSceneView.Repaint(); | |
} | |
} | |
} else { | |
if (_hoveredInstance == instanceID) { | |
_hoveredInstance = 0; | |
if (SceneView.lastActiveSceneView) { | |
SceneView.lastActiveSceneView.Repaint(); | |
} | |
} | |
} | |
break; | |
case EventType.MouseDrag: | |
case EventType.DragUpdated: | |
case EventType.DragPerform: | |
case EventType.DragExited: | |
if (SceneView.lastActiveSceneView) { | |
SceneView.lastActiveSceneView.Repaint(); | |
} | |
break; | |
} | |
} | |
} |
How it works:
When the Unity3D editor loads, it calls the static constructor of this script. Then, the HighlighHelper hooks on to the scene view’s GUI callbacks, editor update callbacks, as well as the editor’s Hierarchy Pane’s item callbacks.
Whenever the Unity3D editor updates, the script checks whether the user is hovering over the hierarchy pane or not. If so, then it allows the window to get MouseMove callbacks. It's hacky, but it works! Then, during the MouseMove events, the script checks if the mouse is inside the rectangle of the name label for any gameobject in the hierarchy, and if so, it notes down which object’s name is hovered over.
The scene view gui method then looks up if any gameobjects match that ‘instance ID’, and draws some circles around them. It does the same for dragged objects. I hope it helps! If you have any questions, please write it in the comments.
Update: I have just created a repository for the script here: https://github.com/toxicFork/Unity3D-HighlightHelper so it will be easier to track any changes or allow any pull requests.
Really helpful. Thanks a lot for the code
This is awesome, thanks :)
Good