如何让场景中Handle始终可见,选中时高亮、悬停时可选中?
Alright, let's tackle these two Handle requirements for your Unity project. I've worked through similar scenarios before, so here's a step-by-step solution with code you can adapt right away.
1. Make Handles Always Visible + Highlight on Selection
By default, Unity only renders Handles when their parent GameObject is selected. To fix this, we'll force-draw the Handles every frame in the OnSceneGUI method of a custom Editor script. We'll also add logic to highlight the Handle when either the GameObject is selected or the mouse is hovering over it.
2. Show Handles Even When GameObject Is Unselected + Hover-to-Select
To let users select the GameObject by clicking the Handle (even if the object wasn't selected before), we'll track mouse interactions with the Handle using Unity's HandleUtility API. This lets us detect when the mouse is over the Handle and trigger a selection on click.
Full Implementation Code
Create a new Editor script (place it in an Editor folder to ensure Unity recognizes it as editor-only code):
using UnityEditor; using UnityEngine; // Replace YourTargetBehaviour with the name of your MonoBehaviour script [CustomEditor(typeof(YourTargetBehaviour))] public class PersistentHandleEditor : Editor { private YourTargetBehaviour _target; private int _handleControlId; private void OnEnable() { _target = (YourTargetBehaviour)target; // Generate a unique control ID for our Handle to track interactions _handleControlId = GUIUtility.GetControlID(FocusType.Passive); } public override void OnSceneGUI() { base.OnSceneGUI(); // Set Handle color based on selection/hover state Handles.color = GetHandleDisplayColor(); // Draw your desired Handle (example: a sphere at the object's position) Vector3 handlePos = _target.transform.position; Handles.SphereHandleCap( _handleControlId, handlePos, Quaternion.identity, 0.5f, // Adjust size as needed EventType.Repaint ); // Handle mouse interaction logic ProcessHandleInteractions(); } private Color GetHandleDisplayColor() { // Check if the GameObject is selected OR the mouse is hovering over the Handle bool isObjectSelected = Selection.activeGameObject == _target.gameObject; bool isHandleHovered = HandleUtility.nearestControl == _handleControlId; return (isObjectSelected || isHandleHovered) ? Color.yellow : Color.gray; } private void ProcessHandleInteractions() { Event currentEvent = Event.current; // If the mouse is over our Handle if (HandleUtility.nearestControl == _handleControlId) { // Make this Handle the default control to capture mouse input HandleUtility.AddDefaultControl(_handleControlId); // Handle left-click to select the GameObject if (currentEvent.type == EventType.MouseDown && currentEvent.button == 0) { Selection.activeGameObject = _target.gameObject; currentEvent.Use(); // Consume the event to prevent unintended actions } } } }
Key Details Explained
- Always Visible Handles: We draw the Handle directly in
OnSceneGUI, which runs every frame regardless of whether the GameObject is selected. No conditional checks for selection state here—we just render it every time. - Highlight Logic: The
GetHandleDisplayColormethod checks two states: if the parent GameObject is selected, or if the mouse is hovering over the Handle (viaHandleUtility.nearestControl). We switch to a bright yellow for these states, gray otherwise. - Hover-to-Select: In
ProcessHandleInteractions, we listen for left-click events when the mouse is over the Handle. When detected, we set the parent GameObject as the active selection and consume the event to avoid selecting other objects in the scene.
Customization Tips
- Change Handle Shape: Replace
Handles.SphereHandleCapwith other built-in Handles likeHandles.CubeHandleCap,Handles.ArrowHandleCap, or even custom mesh/line drawing withHandles.DrawMeshorHandles.DrawLine. - Adjust Sizes/Colors: Tweak the size parameter in
SphereHandleCapor modify the color values inGetHandleDisplayColorto match your project's style. - Multiple Handles: If you need multiple Handles per object, generate a unique control ID for each one (use
GUIUtility.GetControlIDfor each Handle) to avoid interaction conflicts.
内容的提问来源于stack exchange,提问作者Bane




