jairogarcíarincón

Receta 4: Contadores de vida y tiempo


52.2K

Introducción



En esta receta, veremos cómo crear una interfaz de usuario UI que muestre contadores de coleccionables, vidas, y tiempo a nuestro juego.

Además, añadiremos la lógica necesaria para mostrar el tiempo transcurrido en el juego y mensajes a medida que se produzcan ciertos eventos.

Puedes comprobar el objetivo final haciendo clic AQUÍ.

Creación del escenario



Tomaremos como punto de partida la receta 3, ya que en la próxima receta añadiremos los elementos y la lógica necesaria para recoger los coleccionables y premios de nuestro juego.

A partir de la receta 3 y en la escena Juego, vamos a crear un Canvas con los siguientes elementos:

  • Un UI > Text con el nombre Texto Monedas
  • Un UI > Text con el nombre Texto Tiempo
  • Un UI > Text con el nombre Mensajes
  • Un UI > Text con el nombre Vidas

Utiliza los conocimientos adquiridos en las recetas anteriores para crear tu propia versión, pero inicialmente la interfaz de usuario se debería parecer a esto:

Receta 4


El tiempo transcurrido



Para mostrar los diferentes valores, vamos a añadir las siguientes variables públicas para poder compartirlas con el resto de escenas, al inicio del script de GameManager (antes del método Start):

/* Añadir en la declaración de variables de GameManager */
//Variables compartidas en todas las escenas
public float tiempo = 0; //Para contabilizar el tiempo
public bool isJuego = true; //Para saber si estoy jugando y que se incremente el tiempo cuando entre en la escena de Juego
public int vidas = 3; //para contabilizar las vidas
public int monedas = 20; //para contabilizar las monedas restantes


A continuación, crearemos un script llamado Tiempo con el siguiente código:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Tiempo : MonoBehaviour {
//Variable para asociar el objeto Texto Tiempo
public Text textoTiempo;
//Script GameManager
private GameManager gameManager;
void Start () {
//Inicializo el texto del contador de tiempo
textoTiempo.text = "Tiempo: 00:00";
//Capturo el script de GameManager
gameManager = FindObjectOfType<GameManager>();
}
void Update () {
//Escribo tiempo transcurrido (si no se ha acabado el juego)
if (gameManager.isJuego){
textoTiempo.text = "Tiempo: " + formatearTiempo();
}
}
//Formatear tiempo (público porque la necesitaremos más adelante)
public string formatearTiempo(){
//Añado el intervalo transcurrido a la variable tiempo
if (gameManager.isJuego){
gameManager.tiempo += Time.deltaTime;
}
//Formateo minutos y segundos a dos dígitos
string minutos = Mathf.Floor(gameManager.tiempo / 60).ToString("00");
string segundos = Mathf.Floor(gameManager.tiempo % 60).ToString("00");
//Devuelvo el string formateado con : como separador
return minutos + ":" + segundos;
}
}

Para que funcione, en la escena de Juego, debemos aplicar el script al Canvas y asociar el objeto Texto Tiempo a la variable Texto Tiempo del script.

NOTA: A partir de ahora, dado que estamos utilizando variables del GameManager, siempre debemos iniciar el juego desde la escena Preload.


Las vidas



En esta receta, consideraremos que el Jugador comienza con 3 vidas y pierde una cada vez que se sale del Suelo. Esto ocurrirá, al menos en mi caso, cuando el jugador caiga por debajo de 0 en el eje Y (Para comprobarlo en tu caso, mueve el Jugador y comprueba los valores de Position).

Puesto que es el Jugador el que pierde vidas, añadiremos el código necesario en JugadorController, aunque haciendo referencia a variables del GameManager:

/* Añadir en las librerías que se importan al principio del script */
using UnityEngine.UI;
/* Añadir en la declaración de variables de JugadorController */
//Límite en Y del Suelo
int limiteSuelo = 0;
//Script GameManager
private GameManager gameManager;
//Variable para asociar el objeto Texto Vidas
public Text textoVidas;
//variable para la posición inicial del jugador
Vector3 posicionInicial;
/* Añadir en el método Start() */
//Busco y asocio mi script de GameManager
gameManager = FindObjectOfType<GameManager>();
//Inicializo el texto del contador de vidas
textoVidas.text = "Vidas: " + gameManager.vidas;
//Capturo la posición inicial del jugador para cuando pierda una vida poder reposicionarlo
posicionInicial = transform.position;
/* Añadir en el método FixedUpdate() */
//Si ha caído por debajo del suelo, le quito una vida
if (transform.position.y < limiteSuelo) quitarVida();
/* Añadir este método al final de la clase (antes de la llave } de cierre) */
//Quito una vida y muevo al jugador a la posición inicial
void quitarVida(){
//Resto una vida
gameManager.vidas--;
//Actualizo el contador de vidas
textoVidas.text = "Vidas: " + gameManager.vidas;
//Devuelvo el Jugador a su posición inicial y le quito la fuerza
transform.position = posicionInicial;
rb.velocity = Vector3.zero;
}


Para que funcione, lo único que debemos hacer es asociar el objeto Texto Vidas la variable Texto Vidas.

Mensajes



Como habrás podido apreciar, con el código anterior se van restando vidas al Jugador pero el juego no termina nunca. Además, el texto del Mensaje está siempre presente en la pantalla.

Para finalizar la receta, añadiremos la siguiente lógica:

  1. Ocultar al inicio el texto de Mensajes
  2. Comprobar que el Jugador tiene vidas disponibles.
  3. Mostrar un mensaje de juego terminado si no tiene vidas.
  4. Impedir que el jugador se siga moviendo.
  5. Parar el contador de Texto Tiempo.

Nota: Añadiremos la lógica del Texto Coleccionables en la próxima receta.

Para conseguir los 4 primeros objetivos, modificaremos el código de JugadorController. Observa que hemos incorporado el método moverJugador() y hemos trasladado a él toda la lógica relacionada con el movimiento del Jugador. Esto es para poder quitar el movimiento al Jugador cuando se quede sin vidas de una forma más optimizada:

/* Añadir en la declaración de variables */
//Variable para asociar el objeto Mensajes
public Text textoMensajes;
/* Añadir en el método Start() */
//Inicio el texto de mensajes a vacío
textoMensajes.text = "";
/* Sustituir el método FixedUpdate() por el siguiente */
void FixedUpdate () {
//Si quedan vidas
if (gameManager.vidas > 0){
//Muevo el jugador (si tiene vidas)
moverJugador();
//Si ha caído por debajo del suelo, le quito una vida
if (transform.position.y < limiteSuelo) quitarVida();
}
//Si no quedan vidas
else{
//Muestro mensaje
textoMensajes.text = "Juego Terminado";
//Pongo isJuego a false para que deje de contar el script Tiempo
gameManager.isJuego = false;
}
}
/* Añadir el método moverJugador() antes de la llave de cierre } de la clase */
//Lógica necesaria para mover al jugador
void moverJugador(){
//Capturo el movimiento en horizontal y vertical de nuestro teclado
float movimientoH = Input.GetAxis("Horizontal");
float movimientoV = Input.GetAxis("Vertical");
//Genero el vector de movimiento asociado, teniendo en cuenta la velocidad
Vector3 movimiento = new Vector3(movimientoH * velocidad, 0.0f, movimientoV * velocidad);
//Aplico ese movimiento al RigidBody del jugador
rb.AddForce(movimiento);
//Si pulsa el botón de saltar y está en el suelo
if (Input.GetButton("Jump") && isSuelo()){
//Aplico el movimiento vertical con la potencia de salto
rb.velocity += Vector3.up * salto;
}
}


Para que funcione, lo único que falta es asociar el objeto Mensajes la variable Texto Mensajes.

Con esto estaría terminada la receta, aunque todavía quedaría pendiente cambiar a la escena de Créditos y mostrar un resumen del juego, algo que haremos más adelante como ejercicio propuesto, pero que puedes ir planteando hacer por tu cuenta.


Publicado el 29 de Junio de 2025

unity