Información actualizada sobre esta entrada
Este artículo pertenece a una serie que consiste en hacer un juego simple en primera persona acerca de encontrar objetos dentro de un laberinto. Es una de mis primeras series de cuando empecé el canal, ahora he mejorado mucho este proyecto y puedes descargar el código fuente para importarlo en tu propio proyecto de Unity. Algún día vamos a hacer un remake de esta serie, suscríbete a mi canal para estar al tanto del nuevo contenido sobre Blender, Unity y programación.
Sígueme en itch.io y descarga el código fuente de este proyecto
PUEDES TESTEAR ESTE JUEGO AQUÍ. TAL VEZ TARDE UN POCO EN CARGAR
🔻
MOVEMENT: WASD CAMERA LOOK: MOUSE
Introducción al artículo original
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
Vídeo relacionado a este artículo
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.
En la figura 2 podemos observar que estos nuevos campos 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.
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.
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.
Vamos a la jerarquía y seleccionamos el botón «Start», para observar sus propiedades en el inspector.
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.
Ahora utilizando el menú desplegable, podemos acceder a las componentes y sus métodos.
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.
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.
Ahora podemos elegir que se ejecute este método cuando se haga clic en el botón Start.
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.
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.
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.
Con esto se corrige el problema y ya podemos utilizar el botón start para comenzar el juego.
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.
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.
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.
Luego vamos al Script GameControl y pegamos estas instrucciones al final del método endGame que se ejecutará cuando el tiempo se agote.
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.
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.