Why do we need guilayout & editorguilayout?

Domina GUILayout y EditorGUILayout en Unity

13/09/2006

Valoración: 4.92 (7351 votos)

Crear herramientas de editor personalizadas en Unity es una de las habilidades más potentes que un desarrollador puede adquirir. Sin embargo, una de las tareas más tediosas es posicionar cada elemento de la interfaz de usuario (UI) de forma manual. Calcular un `Rect` para cada botón, campo de texto o etiqueta puede volverse rápidamente un proceso engorroso y propenso a errores, especialmente cuando se busca un diseño que se adapte a diferentes tamaños de ventana. Aquí es donde entran en juego dos clases que cambiarán tu forma de trabajar: `GUILayout` y `EditorGUILayout`.

Why do we need guilayout & editorguilayout?
Especially when all that we want is just to put an element after another element relatively without even needing to know the absolute pixel position. This is when GUILayout and EditorGUILayout become handy. They have utility methods that can help us automatically calculate the layout and placing the element.

Estas clases son la respuesta de Unity al diseño de UI automático. En lugar de especificar las coordenadas exactas de cada elemento, simplemente los declaramos en el orden en que queremos que aparezcan, y Unity se encarga de calcular su posición y tamaño. Este enfoque, conocido como diseño de retención inmediata, nos permite construir interfaces complejas de manera mucho más rápida y legible. En este artículo, exploraremos a fondo cómo utilizar estas herramientas para crear layouts verticales, horizontales, anidados y responsivos, transformando por completo tu flujo de trabajo de scripting del editor.

Índice de Contenido

El Diseño Vertical: El Comportamiento por Defecto

Cuando comienzas a utilizar `GUILayout` o `EditorGUILayout`, notarás que el comportamiento predeterminado es apilar los elementos uno debajo del otro. Esto se conoce como un diseño vertical. La mayoría de los métodos de dibujo en estas clases tienen nombres idénticos a sus contrapartes en `GUI` y `EditorGUI`, con la gran diferencia de que no requieren un `Rect` como primer parámetro.

Veamos un ejemplo sencillo en el método `OnGUI` de una ventana de editor:

private void OnGUI() { // Estos campos se dibujarán uno debajo del otro automáticamente exampleFloat = EditorGUILayout.FloatField(new GUIContent("Mi Flotante", "Tooltip para el flotante."), exampleFloat); exampleTransform = EditorGUILayout.ObjectField("Mi Transform", exampleTransform, typeof(Transform), true) as Transform; }

Como puedes ver, sin especificar ninguna posición, Unity los organiza verticalmente. Sin embargo, para tener un mayor control y mejorar la legibilidad del código, es una buena práctica definir explícitamente los bloques de layout. Para un diseño vertical, usamos `GUILayout.BeginVertical()` y `GUILayout.EndVertical()`.

private void OnGUI() { GUILayout.BeginVertical(); { // El resultado es el mismo, pero el código es más claro exampleFloat = EditorGUILayout.FloatField(new GUIContent("Mi Flotante", "Tooltip para el flotante."), exampleFloat); exampleTransform = EditorGUILayout.ObjectField("Mi Transform", exampleTransform, typeof(Transform), true) as Transform; } GUILayout.EndVertical(); }

Es obligatorio cerrar cada bloque `Begin...` con su correspondiente `End...`. Si no lo haces, Unity lanzará un error. El uso de llaves `{}` es una convención personal que ayuda a visualizar claramente dónde empieza y termina un bloque de layout.

Organización Horizontal: Elementos Lado a Lado

Ahora, ¿qué pasa si queremos colocar elementos uno al lado del otro? Para esto, utilizamos un diseño horizontal con `GUILayout.BeginHorizontal()` y `GUILayout.EndHorizontal()`. Todos los elementos que dibujes entre estas dos llamadas se distribuirán horizontalmente.

private void OnGUI() { GUILayout.BeginHorizontal(); { exampleFloat = EditorGUILayout.FloatField(new GUIContent("Mi Flotante"), exampleFloat); exampleTransform = EditorGUILayout.ObjectField("Mi Transform", exampleTransform, typeof(Transform), true) as Transform; } GUILayout.EndHorizontal(); // Este botón vuelve al layout por defecto (vertical) if (GUILayout.Button("Mi Botón")) { Debug.Log("¡Botón presionado!"); } }

En el ejemplo anterior, el campo flotante y el campo de objeto aparecerán en la misma línea. El botón, al estar fuera del bloque horizontal, se dibujará debajo, siguiendo el flujo vertical predeterminado. Recuerda siempre que un `BeginHorizontal` debe cerrarse con un `EndHorizontal`, no con un `EndVertical`.

Añadiendo Espacios para Respirar

Un diseño sin espaciado puede verse abarrotado y poco profesional. `GUILayout` nos ofrece una forma sencilla de añadir espacio: `GUILayout.Space(float pixels)`. Este método añadirá un espacio vertical si se encuentra dentro de un `BeginVertical` o un espacio horizontal si está en un `BeginHorizontal`. También existe `EditorGUILayout.Space()`, que no toma parámetros y utiliza el espaciado estándar del editor.

private void OnGUI() { GUILayout.BeginHorizontal(); { exampleFloat = EditorGUILayout.FloatField(new GUIContent("Mi Flotante"), exampleFloat); GUILayout.Space(20f); // Añade 20 píxeles de espacio horizontal exampleTransform = EditorGUILayout.ObjectField("Mi Transform", exampleTransform, typeof(Transform), true) as Transform; } GUILayout.EndHorizontal(); EditorGUILayout.Space(); // Añade un espacio vertical estándar if (GUILayout.Button("Mi Botón")) { Debug.Log("¡Botón presionado!"); } }

Layouts Anidados: La Clave para Interfaces Complejas

La verdadera potencia de `GUILayout` se revela cuando comenzamos a anidar layouts. Podemos tener un diseño vertical dentro de uno horizontal, y viceversa. Piensa en ello como un sistema de pilas: el último layout que abres (`Begin...`) es el primero que debes cerrar (`End...`). Esto nos permite crear estructuras de UI muy sofisticadas, como columnas y filas complejas.

What's the difference between editorgui and editorguilayout?
Same with EditorGUI and EditorGUILayout, but those are specifically designed for adding GUI in the editor window. They don’t do the same thing…GUI uses absolute rect coordinates, GUILayout is for auto-layout. You use whatever works better for you and your script.

Imaginemos que queremos crear dos columnas, cada una con su propia etiqueta y campo:

private void OnGUI() { // Layout principal horizontal para contener las dos columnas GUILayout.BeginHorizontal(); { // Primera columna (Vertical) GUILayout.BeginVertical(); { EditorGUILayout.LabelField("Columna 1"); exampleFloat = EditorGUILayout.FloatField(new GUIContent("Flotante"), exampleFloat); } GUILayout.EndVertical(); GUILayout.Space(50f); // Espacio entre columnas // Segunda columna (Vertical) GUILayout.BeginVertical(); { EditorGUILayout.LabelField("Columna 2"); exampleTransform = EditorGUILayout.ObjectField("Transform", exampleTransform, typeof(Transform), true) as Transform; } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); }

Con este código, hemos creado una estructura de dos columnas de forma limpia y escalable. Los diseños anidados son fundamentales para organizar la información de manera efectiva en tus herramientas de editor.

Definiendo un Área de Dibujo con `BeginArea`

Por defecto, `GUILayout` utiliza toda la ventana del editor como su área de dibujo. Sin embargo, a veces necesitamos restringir nuestra UI a una sección específica de la ventana, por ejemplo, para crear márgenes o paneles fijos. Para ello, usamos `GUILayout.BeginArea(Rect screenRect)` y `GUILayout.EndArea()`. Todo lo que se dibuje entre estas llamadas estará contenido dentro del `Rect` que especifiquemos, y sus coordenadas serán relativas a esa área, no a la ventana completa.

private void OnGUI() { // Creamos un área con 10 píxeles de margen en todos los lados Rect areaRect = new Rect(10, 10, position.width - 20, position.height - 20); GUILayout.BeginArea(areaRect); { // Todo nuestro código de layout anterior iría aquí dentro EditorGUILayout.LabelField("Contenido con margen"); if (GUILayout.Button("Botón dentro del área")) {} } GUILayout.EndArea(); }

Opciones de Layout: Personalización y Diseño Responsivo

Hasta ahora, hemos dejado que Unity decida el tamaño de los elementos. Pero `GUILayout` nos da un control granular a través de `GUILayoutOption`. Casi todos los métodos de `GUILayout` y `EditorGUILayout` aceptan un array de `GUILayoutOption` como último parámetro. Esto nos permite especificar anchos, altos, expansiones y más.

Algunas de las opciones más comunes son:

  • `GUILayout.Width(float width)`: Especifica un ancho fijo.
  • `GUILayout.Height(float height)`: Especifica una altura fija.
  • `GUILayout.MinWidth(float width)` / `GUILayout.MinHeight(float height)`: El elemento no se encogerá más allá de este tamaño.
  • `GUILayout.MaxWidth(float width)` / `GUILayout.MaxHeight(float height)`: El elemento no se estirará más allá de este tamaño.
  • `GUILayout.ExpandWidth(bool expand)`: Permite o prohíbe que el elemento se expanda horizontalmente para rellenar el espacio disponible.
  • `GUILayout.ExpandHeight(bool expand)`: Permite o prohíbe que el elemento se expanda verticalmente.

Además, existe una herramienta muy útil: `GUILayout.FlexibleSpace()`. Este método crea un espacio vacío que se expande para ocupar todo el espacio sobrante en un layout, empujando a los otros elementos. Es perfecto para alinear elementos a la derecha o para distribuir varios elementos de manera uniforme.

Combinemos todo lo aprendido en un ejemplo final y avanzado:

private void OnGUI() { GUILayout.BeginArea(new Rect(10, 10, position.width - 20, position.height - 20)); GUILayout.BeginHorizontal(); { // Columna 1 con un ancho máximo GUILayout.BeginVertical(GUILayout.MaxWidth(250)); { EditorGUILayout.LabelField("Columna Izquierda"); exampleFloat = EditorGUILayout.FloatField("Flotante", exampleFloat); } GUILayout.EndVertical(); GUILayout.FlexibleSpace(); // ¡Este espacio empuja la siguiente columna a la derecha! // Columna 2 con un ancho máximo GUILayout.BeginVertical(GUILayout.MaxWidth(300)); { EditorGUILayout.LabelField("Columna Derecha"); exampleTransform = EditorGUILayout.ObjectField("Transform", exampleTransform, typeof(Transform), true) as Transform; } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); GUILayout.FlexibleSpace(); // Empuja el botón hacia la parte inferior if (GUILayout.Button("Botón Expansible", GUILayout.Height(40))) { Debug.Log("¡Click!"); } GUILayout.EndArea(); }

Si pruebas este código y redimensionas la ventana del editor, verás cómo el espacio flexible se adapta, manteniendo las columnas en sus respectivos lados y el botón en la parte inferior. Este es el poder del diseño automático y responsivo.

Tabla Comparativa: GUI vs. GUILayout

CaracterísticaGUI / EditorGUIGUILayout / EditorGUILayout
PosicionamientoManual (requiere un Rect)Automático (basado en el flujo)
ComplejidadAlta para layouts dinámicosBaja, ideal para layouts simples y complejos
FlexibilidadControl absoluto a nivel de píxelAlta, con opciones para diseños responsivos
Caso de Uso PrincipalInterfaces superpuestas, HUDs, control totalVentanas de editor, inspectores personalizados

Preguntas Frecuentes (FAQ)

¿Cuál es la diferencia principal entre EditorGUILayout y GUILayout?

Ambas clases gestionan el layout automático. La principal diferencia es que `EditorGUILayout` contiene controles específicos del editor de Unity, como `ObjectField`, `LayerField`, `TagField`, etc., que están diseñados para interactuar con Assets y GameObjects. `GUILayout` contiene controles más genéricos como `Button` y `Label`. Generalmente, para scripting del editor, preferirás usar `EditorGUILayout` siempre que sea posible.

¿Es realmente obligatorio usar `EndVertical` si usé `BeginVertical`?

Sí, absolutamente. El sistema de layouts de Unity funciona como una pila. Cada llamada a `Begin...` empuja un nuevo grupo de layout a la pila. La llamada a `End...` correspondiente lo saca. Si no cierras un grupo que abriste, la pila se corromperá y Unity lanzará un error `ArgumentException: Getting control...`. Siempre asegúrate de que cada `Begin` tenga su `End`.

¿Cuándo debería seguir usando el sistema manual con `Rect`?

Aunque `GUILayout` es increíblemente útil, hay situaciones donde el control manual es preferible. Por ejemplo, si necesitas superponer elementos, crear una interfaz de arrastrar y soltar muy específica, o tener un control total a nivel de píxel sobre la posición de cada elemento, el sistema basado en `Rect` de `GUI` y `EditorGUI` te dará esa flexibilidad que el sistema automático no puede ofrecer.

Si quieres conocer otros artículos parecidos a Domina GUILayout y EditorGUILayout en Unity puedes visitar la categoría Juegos.

Subir