#6 Programar la interfaz de usuario en Unity. [Laberinto en Primera Persona]

Por GameDevTraum

Introducción

En este artículo vamos a programar el funcionamiento de la interfaz de usuario creada en el video 5 de la serie del laberinto. Si no leiste el artículo anterior, en resumen creamos una interfaz de usuario en Unity, que contará con la funcionalidad mínima para que el usuario pueda interactuar con el juego.

Página principal del proyecto

Artículos de la Serie del Laberinto

Antes de comenzar te invito a ver el siguiente video.

Descripción del objetivo

En el artículo anterior diseñamos una interfaz de usuario simple para que el usuario puede controlar los aspectos fundamentales de nuestro juego, como pueden ser iniciar la partida, saber cuánto tiempo le queda, etc.

De momento vamos a utilizar el Script GameControl para manejar la interfaz de usuario. En capítulos siguientes delegaremos esta responsabilidad a un nuevo Script.

Para resumir los elementos de la interfaz de usuario tenemos dos pantallas, una para el menú principal la cual contiene sólo un botón que sirve para iniciar el juego. La segunda pantalla es para la partida y tiene un elemento texto que mostrará la cantidad de tiempo que queda para terminar la partida.

Resolución

En el Script GameControl definimos tres GameObjects serializados, uno para la cámara que está activa en el menú principal, otro para la interfaz del menú y otro para la interfaz de la partida.

Los tres GameObjects definidos están resaltados en la figura 1.

script c# para unity 3d con tres gameobjects seleccionados
Fig. 1: Se definen tres GameObjects serializados para la cámara y las pantallas de la interfaz.

En la figura 2 podemos observar que estos nuevos campos aparecen en el inspector.

inspector en unity 3d, en los espacios se colocarán gameobjects de la interfaz de usuario
Fig. 2: Los tres GameObjects aparecen en el inspector.

Tomamos los objetos creados en el video anterior y los arrastramos a los campos en el inspector. Estos objetos son la cámara, el GameObject MainMenu y el GameObject Game.

jerarquía en unity 3d con game objects
Fig. 3: Tomamos los GameObjects de la jerarquía y los llevamos al inspector.

inspector en unity 3d, se han colocado todos los gameobjects de la interfaz de usuario
Fig. 4: En el inspector colocamos cada GameObject en su espacio correspondiente.

Métodos startGame y endGame

Vamos a definir dos métodos, uno se va a llamar “startGame” y el otro “endGame”. El método startGame tendrá la función de hacer todo lo necesario para que la partida empiece, es decir poner el timer en cero, colocar el prefab del personaje, colocar el pedestal en una posición aleatoria del escenario y demás. Tengamos en cuenta que estas acciones probablemente estarán definidas en otros métodos.

En el método endGame eliminamos todos los objetos del escenario, vamos al menú principal y demás.

La definición de los métodos se muestra en la figura 5. Para ampliar la información hice un video sobre qué es un método en programación y también escribí un artículo para esta página.

script c# para unity 3d metodos startGame y endGame para empezar y terminar juego respectivamente
Fig. 5: Se definen los métodos startGame y endGame.

En los métodos vamos a activar y desactivar los elementos correspondientes, como se observa en la figura 6. Esto tiene que ver con la interfaz de usuario.

script c# para unity 3d metodos startGame y endGame para empezar y terminar juego respectivamente
Fig. 6: Dentro de cada método colocamos las instrucciones apropiadas.

Vamos a la jerarquía y seleccionamos el botón “Start”, para observar sus propiedades en el inspector.

jerarquía en unity 3d con game objects, esta seleccionado el boton start de la interfaz de usuario
Fig. 7: Se selecciona el botón de start en la jerarquía.

inspector en unity 3d con un botón de la interfaz de usuario seleccionado
Fig. 8: En el inspector hacemos clic en el signo más para agregar una función a OnClick().

En la componente Button hay un campo llamado OnClick(), vamos a hacer clic en el signo más de la esquina inferior derecha, en la figura 8 el cursor está sobre este botón.

Esto nos permitirá ejecutar métodos públicos dentro de las componentes del GameObject que asignemos.

En el campo que aparece vamos a colocar el GameObject Control.

inspector del metodo OnClick de button en unity 3d
Fig. 9: Aparece un espacio para colocar un GameObject.

asignacion de un gameobject en el metodo onclick en el inspector de unity 3d
Fig. 10: Colocamos el objeto Control que tiene asignado el Script GameController.

Ahora utilizando el menú desplegable, podemos acceder a las componentes y sus métodos.

selección de función para el método onclick en unity 3d
Fig. 11: Con el menú desplegable se puede seleccionar un método de alguna de las componentes del objeto Control.

Como se trata del botón Start, estamos buscando el método StartGame que hemos definido en el Script GameControl, en la figura 12 podemos observar los atributos y métodos públicos del Script GameControl y vemos que StartGame no se encuentra entre ellos.

selección de función para el método onclick en unity 3d
Fig. 12: El método startGame no aparece entre las funciones.

Esto se debe a que utilizamos visibilidad privada en la definición.

Para solucionar el problema, cambiamos el método a visibilidad pública, como se ve en la figura 14.

script c# para unity 3d metodos startGame y endGame para empezar y terminar juego respectivamente. control de la interfaz de usuario
Fig. 13: Habíamos definido el método startGame como privado.

script c# para unity 3d metodos startGame y endGame para empezar y terminar juego respectivamente. control de la interfaz de usuario
Fig. 14: Cambiamos la visibilidad a público.

Ahora podemos elegir que se ejecute este método cuando se haga clic en el botón Start.

selección de función para el método onclick en unity 3d
Fig. 15: Ahora el método startGame aparece en las funciones.

Acomodo un poco la cámara para que se vea la pequeña escena de las puertas y entro en el modo juego para probar el funcionamiento del botón.

escena en unity 3d vista superior, el suelo es de cesped
Fig. 16: Acomodamos la cámara del menú principal.
prueba de la interfaz grafica en unity 3d
Fig. 17: Entramos en el modo juego para probar el botón.

Corrección de bug

Al entrar en modo juego, el personaje aparece en una de las puertas de manera aleatoria, pero por alguna razón los controles no funcionan correctamente, el personaje se arrastra por el suelo y la cámara gira en una dirección extraña.

bug en unity 3d, el personaje aparece caido en el suelo
Fig. 18: El juego inicia pero parece haber un problema con el personaje.

bug en unity 3d, el personaje aparece caido en el suelo
Fig. 19: El personaje aparece de costado y no puede moverse.

El proceso de Debugging puede llegar a ser algo tortuoso, por suerte tenemos herramientas para analizar el flujo del programa, descubrir las partes del código que funcionan correctamente, ver los valores de las variables y así hasta detectar el problema y poder corregirlo.

Hice un artículo sobre una de estas herramientas de debugging, el método Debug.Log para imprimir datos en pantalla, haz clic en este link para leerlo es una herramienta muy útil!

Sin entrar en detalles, porque sinceramente no recuerdo cómo descubrí el bug, el problema tenía que ver con la estructura de parentezco entre los GameObjects y la transformación herededa del GameObject padre.

Para corregir el problema en la instrucción para instanciar al personaje, dentro del método “placePlayerRandomly”, cambio la rotación de local a global, como se observa en las figuras 20 y 21.

script c# para unity 3d metodo placePlayerRandomly para colocar al jugador aleatoriamente en el escenario
Fig. 20: El método placePlayerRandomly es el que se encarga de colocar al personaje en el escenario.
script c# para unity 3d metodo placePlayerRandomly para colocar al jugador aleatoriamente en el escenario
Fig. 21: En la instrucción instantiate cambiamos localRotation por rotation.

Con esto se corrige el problema y ya podemos utilizar el botón start para comenzar el juego.

modo juego en unity 3d, suelo de cesped con margaritas y una puerta antigua de madera
Fig. 22: Ahora el personaje aparece correctamente en el escenario.

Algunos detalles antes de terminar

Cuando se entra en el modo juego, el prefab del controlador en primera persona captura el cursor, lo coloca en el centro de la pantalla y lo oculta.

Esto es un problema porque al regresar al menú principal cuando se termina la partida no podemos hacer clic en los botones. Así que la solución es desbloquear el cursor y hacerlo visible en el momento en que termina la partida, es decir en el método endGame().

Para descubrir cómo hacer esto vamos a analizar el Script MouseLook que utiliza el controlador en primera persona. En la figura 23 podemos ver este Script junto con su ruta para llegar a él.

cuatro scripts de unity 3d en la ventana proyecto
Fig. 23: Abrimos el Script MouseLook dentro de FirstPersonCharacter de Standard Assets.

Error Fatal

Al intentar abrir MouseLook el editor falla y debe cerrarse perdiéndose todos los cambios no guardados! Es importante guardar en todo momento, el acceso CTRL+S es muy útil.

fallo en editor de scripts mono behaviour durante un proyecto en unity 3d
Fig. 24: Al abrir el script se produce un error y se pierden todos los cambios no guardados.

En el segundo intento fuimos capaces de acceder el Script. Estamos buscando una instrucción relacionada al Cursor.

Vemos que en las líneas 93 y 94 de la figura 26 hay un par de instrucciones que parecen ser las indicadas así que las copiamos.

script mouse look de firstpersoncharacter standard assets
Fig. 25: Revisamos el script MouseLook en busca de las instrucciones que desbloquean el mouse.

dos instrucciones en c# que desbloquean el cursor del mouse y lo desbloquean
Fig. 26: Las dos instrucciones seleccionadas desbloquean el cursor y lo hacen visible.

Luego vamos al Script GameControl y pegamos estas instrucciones al final del método endGame que se ejecutará cuando el tiempo se agote.

script c sharp para unity 3d metodo placePlayerRandomly para colocar al jugador aleatoriamente en el escenario
Fig. 27: Pegamos las instrucciones al final del método endGame.

Finalizar la partida

También vamos a darle al usuario la posibilidad de terminar la partida cuando lo desee utilizando la tecla Escape.

Esto lo hacemos con el método GetKeyDown de la clase Input.

En el primer video de la serie fundamental de Unity explico cómo leer entradas de teclado y mouse, además la diferencia que existe entre los distintos métodos, también hay un artículo sobre el video en esta página.

script c sharp unity 3d metodos update y startGame
Fig. 28: Ejecutamos el método endGame al presionar la tecla escape.

Conclusión

En el artículo analizamos cómo programar la interacción entre los elementos de la interfaz de usuario y el Script GameControl.

En el caso del botón ya está programada la funcionalidad para que ejecute métodos de los Scripts, pero debemos asegurarnos de que estos métodos tengan visibilidad pública.