Soluciones para cada Reto de Unity de Marzo 2024

Soluciones para cada Reto de Unity de Marzo 2024

María Santos María Santos
11 minutos

Leer el artículo
Audio is generated by DropInBlog's AI and may have slight pronunciation nuances. Learn more

Reto 01 (03 / 03 / 2024)

Enunciado

El primer reto del mes consiste en crear un sistema de vidas. Tienes 3 vidas y cada vez que te dañan pierdes 1 vida. Si te quedas sin vidas, Game Over

Solución

Necesitamos dos variables: una que almacene las vidas que tiene nuestro jugador (a la que hemos llamado lives) y otra, que hacemos constante, que guarde la cantidad máxima de vidas que nuestro jugador puede tener (a la que hemos llamado LIVES_MAX).

A continuación, vamos a declarar una función que se encargue de reducir una vida al jugador cada vez que la llamemos. De eso se encarga la primera línea del cuerpo de la función LooseLife. La función no solamente va a hacer eso, sino que también se encargará de mantener el valor de la variable lives entre el mínimo (0) y el máximo. Y eso es precisamente lo que conseguimos con la línea Math.Clamp(lives, 0, LIVES_MAX).

Finalmente, la función comprueba si el jugador se ha quedado sin vidas (si el valor de lives es 0). En ese caso, mostramos el mensaje "GAME OVER" por consola.

using System;
using UnityEngine;

public class LifeManager : MonoBehaviour
{

    private int lives;
    private const int LIVES_MAX = 3;
    
    private void Start()
    {
        lives = LIVES_MAX;
    }

    public void LooseLife()
    {
        lives--;
        lives = Math.Clamp(lives, 0, LIVES_MAX);

        if (lives == 0)
        {
            Debug.Log("GAME OVER");
        }
    }
}

Reto 02 (10 / 03 / 2024)

Enunciado

Dado un sistema de vidas, representa las vidas que te quedan con un texto TMPro

Solución

Necesitamos manipular el campo de texto de una componente TextMeshProUGUI, por lo que necesitamos una variable de tipo TextMeshProUGUI que guarde la referencia de la componente TextMeshProUGUI cuyo campo de texto queremos modificar.

Al tratarse de una función que modifica un texto cuyo valor lo gestiona otro script, tiene que ser pública. Y el valor a mostrar le viene por parámetro. Si suponemos que el sistema de vidas es el realizado en el Reto 01, entonces ese parámetro tiene que ser de tipo int.

Para acabar, hemos hecho que UIManager sea un singleton, para llamarlo desde otro script (como por ejemplo, desde LifeManager cada vez que modificamos el valor de la variables lives, la que gestiona las vidas del jugador).

using TMPro;
using UnityEngine;

public class UIManager : MonoBehaviour
{
    public static UIManager Instance { get; private set; }
    
    [SerializeField] private TextMeshProUGUI livesText;

    private void Awake()
    {
        if (Instance != null)
        {
            Debug.LogError("More than one instance");
        }

        Instance = this;
    }

    public void UpdateLivesText(int lives)
    {
        livesText.text = lives.ToString();
    }
}

A continuación es como quedaría el script LifeManager del Reto 01 con las llamadas pertinentes a UpdateLivesText.

using System;
using UnityEngine;

public class LifeManager : MonoBehaviour
{

    private int lives;
    private const int LIVES_MAX = 3;
    
    private void Start()
    {
        lives = LIVES_MAX;
        UIManager.Instance.UpdateLivesText(lives);
    }

    public void LooseLife()
    {
        lives--;
        lives = Math.Clamp(lives, 0, LIVES_MAX); 
        UIManager.Instance.UpdateLivesText(lives);

        if (lives == 0)
        {
            Debug.Log("GAME OVER");
        }
    }
}

Reto 03 (17 / 03 / 2024)

Enunciado

Dado un sistema de vidas, representa las vidas que te quedan con imágenes

Solución

Para empezar, vamos a necesitar tantas imágenes en la UI como vidas pueda tener el jugador. Si suponemos que el sistema de vidas es el realizado en el Reto 01, entonces como máximo podemos a llegar a tener 3 vidas.

En nuestro caso, hemos creado un objeto vacío al que hemos llamado Lives Images como hijo del Canvas que tiene la componente Horizontal Layout Group para así no tener que preocuparnos de la disposición de las imágenes que representan las vidas. Eso sí, nos hemos cerciorado de que las 3 imágenes, hijas de Lives Images, de 100 píxeles de anchura por 100 píxeles de altura caben. Por ello, la anchura de Lives Images es de 400 píxeles (para que haya separación entre los hijos) y la altura, de 100 píxeles. Finalmente, como hemos situado en la esquina superior izquierda el objeto Lives Images, la alineación que hemos elegido para los hijos en la componente Horizontal Layout Group es Middle Left.

Además, necesitaremos referencia a cada una de esas imágenes. Por ello, creamos un array de Game Objects del mismo tamaño que el número total de vidas que podemos tener y lo haremos en el UIManager. Las referencias las asignaremos a través del inspector.

Al tratarse de una función que depende de un valor gestionado por otro script, tiene que ser pública. Y el valor en cuestión le viene por parámetro. Si suponemos que el sistema de vidas es el realizado en el Reto 01, entonces ese parámetro tiene que ser de tipo int.

¿Y qué hace esta función? Pues muestra tantas imágenes como vidas tenga el jugador. Por tanto, si consideramos que la imagen de vida en el índice 0 del array es la última que se pierde, lo que haremos será dejar los Game Objects activados desde el índice 0 hasta el índice que viene por parámetro menos 1 y el resto de Game Objects, los desactivaremos para que dejen de ser visibles. Esto es, si tenemos un total de 3 vidas y por parámetro llega un 1, dejaremos activo solo el primer Game Object del array y el resto los desactivaremos con SetActive(false), para así únicamente mostrar una vida.

Para acabar, hemos hecho que UIManager sea un singleton, para llamarlo desde otro script (como por ejemplo, desde LifeManager cada vez que modificamos el valor de la variables lives, la que gestiona las vidas del jugador).

using UnityEngine;

public class UIManager : MonoBehaviour
{
    public static UIManager Instance { get; private set; }
    
    [SerializeField] private GameObject[] livesImagesArray = new GameObject[LifeManager.LIVES_MAX];

    private void Awake()
    {
        if (Instance != null)
        {
            Debug.LogError("More than one instance");
        }

        Instance = this;
    }

    public void UpdateLives(int lives)
    {
        for (int i = 0; i < livesImagesArray.Length; i++)
        {
            livesImagesArray[i].SetActive(i < lives);
        }
    }
}

A continuación es como quedaría el script LifeManager del Reto 01 con las llamadas pertinentes a UpdateLives.

using System;
using UnityEngine;

public class LifeManager : MonoBehaviour
{
    public const int LIVES_MAX = 3;
    
    private int lives;
    
    private void Awake()
    {
        lives = LIVES_MAX;
        UIManager.Instance.UpdateLives(lives);
    }

    public void LooseLife()
    {
        lives--;
        lives = Math.Clamp(lives, 0, LIVES_MAX); 
        UIManager.Instance.UpdateLives(lives);

        if (lives == 0)
        {
            Debug.Log("GAME OVER");
        }
    }
}

Hemos hecho pública la constante LIVES_MAX para poder acceder a ella desde UIManager y declarar así el array de vidas y que coincida el número de vidas máximas con el número total de imágenes.

Reto 04 (24 / 03 / 2024)

Enunciado

Crea un sistema de vida. Tienes 100 puntos de vida y cada vez que te dañan pierdes 10 puntos de vida. Si te quedas sin vida, Game Over

Solución

Este reto es muy similar al Reto 01. Necesitamos dos variables: una que almacene la vida que tiene nuestro jugador (a la que hemos llamado health) y otra, que hacemos constante, que guarde la cantidad máxima de vida que nuestro jugador puede tener (a la que hemos llamado HEALTH_MAX).

A continuación, vamos a declarar una función que se encargue de reducir 10 puntos de vida al jugador cada vez que la llamemos. De eso se encarga la primera línea del cuerpo de la función ReceiveDamage. La función no solamente va a hacer eso, sino que también se encargará de mantener el valor de la variable health entre el mínimo (0) y el máximo. Y eso es precisamente lo que conseguimos con la línea Math.Clamp(health, 0, HEALTH_MAX).

Finalmente, la función comprueba si el jugador se ha quedado sin vida (si el valor de health es 0). En ese caso, mostramos el mensaje "GAME OVER" por consola.

using System;
using UnityEngine;

public class LifeManager : MonoBehaviour
{
    public const int HEALTH_MAX = 100;
    
    private int health;
    
    private void Awake()
    {
        health = HEALTH_MAX;
    }

    public void ReceiveDamage()
    {
        health -= 10;
        health = Math.Clamp(health, 0, HEALTH_MAX);

        if (health == 0)
        {
            Debug.Log("GAME OVER");
        }
    }
}

Reto 05 (31 / 03 / 2024)

Enunciado

Dado un sistema de vida, representa la vida con una barra de vida

Solución

Vamos a hacer la barra de vida con un Slider al que vamos a llamar Health Bar. Lo primero es quitar el check Interactable de la componente Slider. Luego, vamos a eliminar el Game Object Handle Slide Area que viene por defecto como hijo del Game Object Slider. Además, para que la barra de vida se vea correctamente, hay que pasar todos los valores Left / Right / Bottom / Top de la componente Rect Transform de los Game Objects Fill Area  y Fill a 0. Finalmente, modificamos el color de Background a un tono rojizo y el de Fill a un tono verdoso.

Necesitamos manipular el valor del Slider, por lo que necesitamos una variable de tipo Slider que guarde la referencia de la componente Slider cuyo valor queremos modificar.

Al tratarse de una función que modifica un valor cuyo valor lo gestiona otro script, tiene que ser pública. Y el valor en cuestión le viene por parámetro. Si suponemos que el sistema de vida es el realizado en el Reto 04, entonces ese parámetro tiene que ser de tipo int. No obstante, el Slider se mueve entre 0 y 1, mientras que la vida del Reto 04 se mueve entre 0 y 100. Es por ello que hacemos la operación (float)health / LifeManager.HEALTH_MAX, para pasar del intervalo [0, 100] al intervalo [0, 1].

Para acabar, hemos hecho que UIManager sea un singleton, para llamarlo desde otro script (como por ejemplo, desde LifeManager cada vez que modificamos el valor de la variable health, la que gestiona la vida del jugador).

using UnityEngine;
using UnityEngine.UI;

public class UIManager : MonoBehaviour
{
    public static UIManager Instance { get; private set; }

    [SerializeField] private Slider healthBar;

    private void Awake()
    {
        if (Instance != null)
        {
            Debug.LogError("More than one instance");
        }

        Instance = this;
    }

    public void UpdateHealth(int health)
    {
        healthBar.value = (float) health / LifeManager.HEALTH_MAX;
    }
}

A continuación es como quedaría el script LifeManager del Reto 01 con las llamadas pertinentes a UpdateLives.

using System;
using UnityEngine;

public class LifeManager : MonoBehaviour
{
    public const int HEALTH_MAX = 100;
    
    private int health;
    
    private void Awake()
    {
        health = HEALTH_MAX;
        UIManager.Instance.UpdateHealth(health);
    }

    public void ReceiveDamage()
    {
        health -= 10;
        health = Math.Clamp(health, 0, HEALTH_MAX);
        UIManager.Instance.UpdateHealth(health);

        if (health == 0)
        {
            Debug.Log("GAME OVER");
        }
    }
}

Comparte tus Soluciones

¿Has conseguido resolver todos los retos? ¿Has encontrado una solución diferente a las propuestas? Pues no dudes en compartir esas soluciones con nosotros. Puedes hacerlo comentando este mismo post o respondiendo a cualquier publicación de nuestras redes sociales.

¡Anímate!

Aprende Unity con Frogames

¿Se te ha complicado algún reto? ¿No sabes exactamente cómo enfocar la solución? ¿No acabas de entender alguna línea de código de las soluciones propuestas?

Si quieres ser capaz de resolver todos estos retos, quieres iniciarte en el mundo del desarrollo de videojuegos con Unity o bien quieres mejorar tus habilidades en este mundillo, entonces visita la Ruta de Desarrollo de Videojuegos donde tenemos toda una parte dedicada al desarrollo de videojuegos con Unity.

En cada curso aprenderás a desarrollar nuevas mecánicas y diferentes tipos de videojuegos. Hay un poco de todo: videojuegos 2D, videojuegos 3D, juegos en primera persona, juegos en tercera persona, shooters, RPGs, clásicos retro...

Además, al inscribirte a alguno de nuestros cursos tendrás acceso a la comunidad de videojuegos para hacernos cualquier duda que te surja durante tu aprendizaje y, sobre todo, para compartir con nosotros y el resto de estudiantes tus avances y tus proyectos.

¿Te lo vas a perder? ¡Nos vemos en clase!

« Volver al Blog

Obtener mi regalo ahora