Menús personalizados con MenuItem en Unity

Resumen

Crear herramientas personalizadas dentro del editor de Unity acelera tu flujo de trabajo y reduce errores repetitivos. Con el atributo MenuItem puedes invocar métodos desde menús del editor, validar cuándo aparecen activos y hasta integrarlos como menús contextuales de cualquier componente. Esta guía es para desarrolladores que ya conocen context menu y quieren llevar sus utilidades un paso más allá.

Qué es un MenuItem en Unity y para qué sirve

Un MenuItem es un atributo que coloca una función dentro de un menú del editor de Unity siguiendo una ruta que tú defines. A diferencia del context menu, que vive atado a un componente específico, el MenuItem puede llamarse desde cualquier parte del editor porque vive en una clase de utilería.

¿Por qué la función de un MenuItem debe ser estática? Porque Unity necesita poder ejecutarla sin instanciar la clase. Así puedes invocarla aunque no exista ningún objeto en escena que la contenga.

En la práctica, esto te permite separar el código de tus herramientas en una clase aparte, mantener el proyecto más ordenado y reutilizar utilidades entre escenas.

Cómo defino la ruta de un MenuItem

La ruta es el primer parámetro del atributo y decide dónde aparece tu opción dentro del editor [02:30]. Algunas reglas útiles:

  • Si usas una categoría existente como GameObject/, tu opción se integra dentro de ese menú nativo.
  • Si inventas una ruta nueva como Tools/Limpiar hijos, Unity crea esa pestaña por ti.
  • Si omites la categoría, la opción aparece directamente en la barra superior junto a las nativas.

Un ejemplo típico es una función LimpiarHijos que toma la selección activa con Selection, recorre los hijos del GameObject y los elimina. Al estar bajo Tools/, aparece como una pestaña nueva lista para usarse [01:10].

Cómo funcionan las funciones de validación en MenuItem

A veces quieres que tu opción aparezca en gris cuando no tiene sentido ejecutarla, por ejemplo cuando el objeto seleccionado no tiene hijos. Para eso existen las funciones de validación [03:20].

La receta es sencilla:

  1. Duplicas el atributo MenuItem con la misma ruta exacta.
  2. Activas el segundo parámetro del constructor como true para indicar que es validación.
  3. La función debe retornar un bool: true habilita la opción, false la muestra en gris.

¿Cómo sé si mi MenuItem necesita validación? Si tu función depende del estado actual de la escena o de la selección, agrega validación. Evita errores de ejecución y comunica visualmente cuándo la herramienta es útil.

Dentro de la validación es común revisar Selection.activeTransform, comprobar que no sea nulo y verificar condiciones como childCount > 0 antes de devolver true.

Cómo creo un MenuItem con prioridad y MenuCommand

El atributo MenuItem acepta un tercer parámetro: la prioridad [04:45]. Este número decide la posición relativa de tu opción dentro del menú. Una prioridad de 10 la coloca cerca del inicio; números más altos la empujan hacia abajo.

Dentro del método puedes recibir un parámetro especial llamado MenuCommand. Este objeto puede llegar:

  • Vacío, cuando llamas la opción desde la barra superior del editor.
  • Con un GameObject de contexto, cuando haces clic derecho sobre un objeto en la jerarquía.

Un caso real: una función CustomGameObject bajo GameObject/MyCategory/CustomGameObject que crea un objeto vacío. Si la llamas desde la barra, el objeto nace en la raíz de la escena. Si la llamas con clic derecho sobre un GameObject, nace como hijo de ese objeto gracias a GameObjectUtility.SetParentAndAlign [06:10].

No olvides registrar la creación con Undo.RegisterCreatedObjectUndo para que Unity reconozca la acción y permita revertirla con Ctrl+Z.

Cuándo usar context dentro de un MenuItem

Si prefijas la ruta con CONTEXT/NombreDelComponente/, tu MenuItem se comporta como un menú contextual del Inspector [07:30]. La diferencia clave frente a un context menu tradicional es que sigue siendo estático y vive en una clase aparte, así separas la lógica de tus herramientas del componente al que afectan.

Ejemplo: CONTEXT/Transform/Crear hijo añade una opción al engranaje del Transform que crea un hijo bajo el objeto seleccionado.

Cómo crear una sombra falsa para un Sprite con MenuItem

Un ejemplo práctico: agregar la opción Crear sombra al menú contextual de cualquier SpriteRenderer. La idea es duplicar el sprite, oscurecerlo y desplazarlo para simular una sombra sin necesidad de iluminación real [09:15].

Los pasos dentro del método son:

  • Castear MenuCommand.context a SpriteRenderer para identificar el sprite original.
  • Crear un GameObject hijo y agregarle un nuevo SpriteRenderer.
  • Copiar el mismo sprite al nuevo renderer.
  • Cambiar el color a negro y reducir el sorting order para que quede detrás.
  • Ajustar la posición para que la sombra se proyecte ligeramente desplazada.

En el editor lo ves en acción: seleccionas un sprite, clic derecho sobre el componente, eliges Crear sombra y aparece el efecto. Si te queda muy intensa o muy grande, ajustas valores en el código y queda lista como herramienta reutilizable.

Este patrón abre un abanico amplio: puedes crear outlines, generadores de prefabs, herramientas para 3D o automatizaciones para componentes que uses a diario. ¿Qué herramienta te haría la vida más fácil en tu proyecto? Déjala en los comentarios para discutirla con la comunidad.