GUI 2D en juego 3D parte 2

Si hacemos clic en el botón se sombreará. Para modificar el tiempo que tarda en sombrearse modificamos la opción Fade Duration. Sin embargo, por mucho que pulsemos el botón no sucederá nada, ya que aún no hemos asignado nada a nuestro botón. La programación de la interacción del UI sigue una serie de pasos para cualquiera de sus elementos:

  1. Crear un objeto de la UI en la scene (por ejemplo nuestro botón).
  2. Escribir un script para llamar cuando la UI esté funcionando.
  3. Adjuntar ese script a un objeto de la scene.
  4. Unir los elementos de la UI al objeto con ese script.

Empezaremos creando un objeto controlador para unir al botón. Creamos un script llamado UIController y soltamos ese script en el objeto controlador en la escena. El código del script es el siguiente:

using UnityEngine;
using UnityEngine.UI;  // Importa el código del framework de UI
using System.Collections;

public class UIController : MonoBehaviour
{
[SerializeField] private Text scoreLabel;  // Hace referencia al objeto Text en la scene
                                           // para ajustar la propiedad del texto.
void Update()
{
scoreLabel.text = Time.realtimeSinceStartup.ToString();
}

public void OnOpenSettings() // Método llamado por el botón de ajustes
{
Debug.Log("open settings");
}
}

Ahora arrastramos el objeto Text de nuestro UI al hueco Score Label de nuestro script. Ahora mismo este texto será un contador debido al código del script.

texto_contador

A continuación añadimos una entrada OnClick al botón. Las entradas OnClick serán ejecutadas cuando se pulse el botón al que pertenecen. Cada entrada tendrá un hueco para el objeto y un menú para seleccionar la función a llamar; arrastramos el objeto controlador al hueco de la entrada y seleccionamos la función OnOpenSettings( ) de UIController. Si ahora ejecutamos el juego y pulsamos el botón se nos mostrará en Console el mensaje «open settings» (función OnOpenSettings( ) de UIController.cs).

entrada_onclick

Creamos ahora otra imagen para nuestro UI (GameObject>UI>Image) y le asignamos un sprite. Por defecto, la imagen asignada ocupará todo el espacio previamente asignado a esa objeto imagen. Para que tome sus valores originales le damos a la opción Set Native Size. La opción Image Type por defecto será Simple, pero puesto que esta imagen la usaremos como ventana pop-up la cambiaremos a Sliced. Nos aparecerá una advertencia: «This Image doesn’t have a border». En Project seleccionamos la imagen y hacemos clic en el botón Sprite Editor que aparece en Inspector y nos abrirá la ventada de Sprite Editor. Una imagen de tipo Sliced debe estar dividida en 9 secciones. Por lo tanto, en el Sprite Editor dividiremos la imagen en 9 secciones asignándole un valor de 12 píxeles a las cuatro líneas que aparecerán (L T R B). Ahora ya no aparecerá la advertencia y la imagen funcionará perfectamente. La redimensionaremos al tamaño que deseemos para la ventana pop-up (250 ancho, 200 alto y posición 0,0,0).

sprite editor

Ahora crearemos un script llamado SettingsPopup y lo añadiremos al objeto pop-up. El código del script será el siguiente:

using UnityEngine;
using System.Collections;

public class SettingsPopup : MonoBehaviour
{
public void Open()
{
gameObject.SetActive(true); // Activa el objeto para abrir la ventana.
}
public void Close()
{
gameObject.SetActive(false); // Desactiva el objeto para cerrar la ventana.
}
}

Lo siguiente será modificar el script UIController de este modo:

...

[SerializeField] private SettingsPopup settingsPopup;

void Start()
{
settingsPopup.Close (); // Cierra el pop-up cuando empieza el juego.
}

...

public void OnOpenSettings()
{
settingsPopup.Open (); // Reemplaza el texto Debug con el método de pop-up.
}

Se creará un nuevo hueco en UIController al que debemos arrastrar el objeto pop-up. Ahora el pop-up se cerrará al iniciar el juego y se abrirá cuando le demos al botón. Para cerrarlo crearemos un botón que situaremos en la esquina superior derecha del pop-up y en su texto pondremos «Cerrar» y le cambiaremos el color a blanco. Añadiremos una entrada OnClic y arrastraremos el objeto pop-up y seleccionaremos la funcion Close( ) para cerrarlo. Ahora cuando pulsemos este botón «Cerrar» el pop-up se cerrará.

Ahora crearemos un objeto Text, InputField y Slider para el UI; el texto será para identificar el slider. Todos estos objetos se crearán desde GameObject>UI. Todos serán hijos del objeto pop-up. En el texto del objeto Text pondremos «Velocidad» y en el de InputField>Placeholder escribiremos «Nombre» (este será el texto que el jugador ve antes de escribir nada). En las opciones del slider le pondremos de valor máximo 2 y marcaremos la opción Whole Numbers, de este modo no tomará decimales y se limitará a los valores [0 1 2] en este caso.

popup

Lo siguiente será escribir el código para los objetos creados. Añadiremos al script SettingsPopup lo siguiente:

...

public void OnSubmitName(string name) // Esto se lanzará cuando el usuario escriba su nombre.
{
Debug.Log(name);
}

public void OnSpeedValue(float speed) // Esto se lanzará cuando el usuario ajuste el slider.
{
Debug.Log("Speed: " + speed);
}

...

Seleccionando el inputfield podemos ver en Inspector un panel End Edit; los eventos que pongamos aquí se lanzarán cuando el jugador acabe de escribir. Añadimos una entrada, arrastramos el objeto pop-up al hueco y elegimos OnSubmitName( ) como función; la función será elegida en la sección de arriba (Dynamic strings) y no la de abajo (Static strings).

dynamic-string

Mismo proceso con el slider pero en el panel On Value Changed. Añadimos la entrada, arrastramos el objeto pop-up y elegimos OnSpeedValue( ) en la lista de valores dinámicos (sección superior). Si lanzamos el juego, introducimos un nombre en inputfield y pulsamos enter, se mostrará por Console ese nombre. Lo mismo si seleccionamos un valor en el slider.

Para alertar a la UI de las acciones de la scene, vamos a usar un broadcast messenger system. En la imagen se ve cómo funciona: los scripts pueden registrar para escuchar a un evento, otro código puede retransmitir un evento, y los listeners (los que «escuchan») serán alertados acerca de los mensajes de la retransmisión.

messenger system

El messenger system que usaremos lo encontramos en http://wiki.unity3d.com/index.php/CSharpMessenger_Extended. Crearemos un script llamado Messenger y guardaremos el código del enlace en él. También crearemos un script llamado GameEvent:

public static class GameEvent
{
public const string PRESS_BUTTON = "PRESS_BUTTON";
public const string SPEED_CHANGED = "SPEED_CHANGED";
}

Este script define una constante para un par de mensajes de evento; los mensajes están así más organizados y no necesitamos recordar y escribir el mensaje por todo el lugar.

Hasta ahora en el texto del UI se mostraba un contador para probar su funcionalidad. Pero ahora mostrará el número de veces que hacemos clic derecho con el ratón. Deberemos modificar UIController.cs para ello:

...

private int _score;

void Awake()
{                                                            // Declara qué metodo responde
Messenger.AddListener(GameEvent.PRESS_BUTTON, OnRightClick); // al evento PRESS_KEY
}
void OnDestroy()
{                                                              // Cuando un objeto es destruido,
Messenger.RemoveListener(GameEvent.PRESS_BUTTON, OnRightClick);// usamos un limpiador de listener
}                                                              // para evitar errores.

void Start()
{
_score = 0;                            // Inicializa el score a 0.
scoreLabel.text = _score.ToString ();

settingsPopup.Close ();
}

private void OnRightClick()
{
_score += 1;                           // Incrementa el score en respuesta al evento.
scoreLabel.text = _score.ToString();
}

...

El método Update( ) ha sido eliminado. Los métodos Awake( ) y OnDestroy( ) funcionarán como todo MonoBehaviour, como por ejemplo Start( ) o Update( ), de manera automática al crearse y destruirse el objeto. Un listener es añadido y eliminado en Awake( ) / OnDestroy( ). El listener es parte del broadcast messenger system, y llama a OnRightClick( ) cuando ese mensaje es recibido, que incrementará la puntuación y la mostrará en el marcador.

A continuación crearemos un script llamado IfRightClick. Este script simplemente comprobará si pulsamos el clic derecho del ratón y retransmitirá un mensaje de ser así. De este modo, cada vez que hagamos clic derecho en el juego, la puntuación de la esquina superior izquierda aumentará en 1. Este script lo añadiremos a nuestro personaje.

using UnityEngine;
using System.Collections;

public class IfRightClick : MonoBehaviour
{
void Update ()
{
if (Input.GetButtonDown ("Fire2"))
{
Messenger.Broadcast(GameEvent.PRESS_BUTTON);
}
}
}

Hemos visto cómo es recibido por el HUD un mensaje retransmitido por la scene. Veremos ahora el caso contrario, el HUD retransmite un mensaje a la scene. En nuestro ejemplo haremos que el slider sea un selector que indicará el número de veces que se llamará el evento PRESS_BUTTON si hacemos clic derecho con el ratón. Modificaremos IfRightClick.cs de la siguiente manera:

using UnityEngine;
using System.Collections;

public class IfRightClick : MonoBehaviour
{
private float speed;
int i;

void Awake()
{
Messenger<float>.AddListener(GameEvent.SPEED_CHANGED, OnSpeedChanged);
}

void OnDestroy()
{
Messenger<float>.RemoveListener(GameEvent.SPEED_CHANGED, OnSpeedChanged);
}

private void OnSpeedChanged(float value)
{
speed = value;
}

void Update ()
{
if (Input.GetButtonDown ("Fire2"))
{
for(i=(int)speed; i > 0; i--)
{
Messenger.Broadcast(GameEvent.PRESS_BUTTON);
}
}
}
}

Awake( ) y OnDestroy( ) añadirán y eliminarán, respectivamente, un event listener como en el caso anterior, pero los métodos tendrán un valor esta vez (OnSpeedChanged). También añadimos el método OnSpeedChanged que igualará el valor de speed al valor obtenido del slider (incialmente 0). Por último, hemos modificado Update( ) para que llame al evento PRESS_BUTTON las veces que indique la variable speed.

Finalmente en SettingsPopup.cs cambiaremos el contenido del método OnSpeedValue( ), añadiéndole un broadcast para enviar el mensaje del evento SPEED_CHANGED.

public void OnSpeedValue(float speed)
{
Messenger<float>.Broadcast(GameEvent.SPEED_CHANGED, speed);
}

Si ahora corremos el juego, dependiendo del valor del slider (0, 1 ó 2) el marcador se actualizará con cada clic que hagamos (añadiendo 0 si la posición del slider es 0, 1 para 1 y 2 para 2).

Deja un comentario