Handles para mover waypoints en Unity

Resumen

Los handles en Unity son la herramienta que necesitas cuando quieres editar objetos directamente desde la escena sin perder tiempo seleccionando piezas individuales. Aprenderás a dibujar trazos visuales, crear controles de posición arrastrables y registrar cambios en el sistema Undo de Unity, ideal para desarrolladores que construyen herramientas de edición más amigables.

Qué son los Handles y en qué se diferencian de los Gizmos

Los handles son representaciones visuales que puedes colocar en la escena, igual que los gizmos, pero con una diferencia clave: aceptan inputs. Eso significa que puedes arrastrarlos, rotarlos o crear controles personalizados similares a los que Unity usa por defecto para mover y rotar objetos.

Piensa en un personaje con rig completo. Si quieres mover solo el brazo o la pierna, lo tradicional sería seleccionar cada hueso. Con un handle personalizado, puedes exponer controles directamente sobre el rig y editar todo sin perder el contexto visual [00:35].

¿Cuál es la diferencia entre Handles y Gizmos en Unity? Los gizmos solo dibujan elementos visuales, mientras que los handles permiten interacción del usuario, como arrastrar un punto para cambiar su posición.

Cómo dibujar el trazado de waypoints con Handles

En el ejemplo trabajamos con un zombi que se mueve de forma periódica entre puntos de control definidos en una lista de transforms. El problema es que sin visualización no sabes por dónde va a pasar.

La solución se escribe dentro de OnSceneGUI en el custom editor, no en el bloque de gizmos, porque solo desde ahí puedes aprovechar los inputs de los handles [04:10].

El flujo para dibujar el camino es así:

  1. Recorrer la lista de waypoints con un for.
  2. Tomar el waypoint actual y calcular el siguiente usando el operador módulo (%) para que regrese al inicio cuando llegue al final del array.
  3. Validar que ninguno sea nulo para evitar crashes.
  4. Dibujar la línea con Handles.DrawDottedLine, que recibe dos posiciones y un tamaño de pantalla.

csharp for (int i = 0; i < zombie.Waypoints.Count; i++) { Transform waypoint = zombie.Waypoints[i]; Transform nextWaypoint = zombie.Waypoints[(i + 1) % zombie.Waypoints.Count];

if (waypoint == null) continue; if (nextWaypoint == null) continue; Handles.color = Color.white; Handles.DrawDottedLine(waypoint.position, nextWaypoint.position, 5f);

}

El color funciona igual que con gizmos, así que puedes asignar blanco para que resalte sobre la escena [06:20].

Cómo agregar un PositionHandle interactivo

Las líneas punteadas ya muestran el recorrido, pero editar los puntos desde la jerarquía sigue siendo engorroso. Aquí entra Handles.PositionHandle, el mismo control que usa Unity para mover objetos.

La función pide una posición y una rotación, y retorna un Vector3 con la nueva posición:

csharp Vector3 newPosition = Handles.PositionHandle(waypoint.position, waypoint.rotation); waypoint.position = newPosition;

Un detalle importante: si intentas dibujar gizmos dentro del custom editor aparece el error "Gizmo drawing function can only be used on drawn gizmos". La esfera amarilla que marca cada punto debe ir en OnDrawGizmosSelected dentro del MonoBehavior del zombi, recorriendo los waypoints con un foreach [09:15].

¿Dónde debo dibujar los Gizmos en un Custom Editor? Los gizmos van en OnDrawGizmos u OnDrawGizmosSelected del MonoBehavior, no en OnSceneGUI del editor. Ahí solo dibujas handles.

Cómo registrar cambios con BeginChangeCheck y Undo

Mover un handle sin más rompe algo crítico: Unity no detecta el cambio. Si presionas Ctrl+Z, no pasa nada, porque el sistema nunca registró la modificación.

La solución combina dos clases: EditorGUI para detectar cambios y Undo para registrarlos.

  • EditorGUI.BeginChangeCheck() le avisa a Unity que vas a vigilar un cambio.
  • EditorGUI.EndChangeCheck() retorna un booleano que es true cuando el valor cambió.
  • Undo.RecordObject(objeto, "nombre de la acción") guarda el estado anterior para que el sistema pueda revertirlo.

csharp EditorGUI.BeginChangeCheck(); Vector3 newPosition = Handles.PositionHandle(waypoint.position, waypoint.rotation); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(waypoint, "Move Waypoint"); waypoint.position = newPosition; }

El nombre que pasas a RecordObject aparece en el menú Edit de Unity como "Move Waypoint", y desde ahí puedes deshacer y rehacer con normalidad [12:40].

¿Por qué usar BeginChangeCheck antes de RecordObject? Porque registrar un objeto en cada frame consume muchos recursos. BeginChangeCheck solo dispara el guardado cuando hay un cambio real.

Por qué este patrón mejora tus herramientas de edición

Dibujar el trazo, exponer controles arrastrables y respetar el sistema Undo convierte una escena confusa en una herramienta cómoda. Tu yo del futuro y cualquier persona que trabaje contigo van a agradecer no tener que cazar transforms en la jerarquía.

Algunas ideas para experimentar:

  • Probar otros tipos de línea disponibles en Handles además de DrawDottedLine.
  • Cambiar el color y el tamaño según el estado del waypoint.
  • Agregar handles de rotación o escala usando Handles.RotationHandle o Handles.ScaleHandle.

¿Qué herramienta de edición personalizada construirías tú con handles? Cuéntanos en los comentarios qué workflow te gustaría simplificar.