Saltar a contenido

Módulo 5 — Colisiones y puntaje (25 min)

¿Qué vamos a lograr?

Que al destruir un enemigo de un disparo, se sumen puntos y se vean reflejados al instante en un marcador en la esquina de la pantalla.

5.1 Crear el GameManager (y por qué es un "Singleton")

Hasta ahora, cada vez que un script necesitaba usar otro (por ejemplo, PlayerController necesitando el bulletPrefab), lo conectamos a mano arrastrándolo en el Inspector. Para el puntaje vamos a usar un enfoque distinto: un Singleton, un único GameManager al que cualquier script puede acceder desde código, sin que nosotros conectemos nada.

  1. En la Hierarchy, clic derecho > Create Empty. Renómbralo a GameManager.
  2. Arrastra el script GameManager.cs sobre él (todavía no le asignamos el campo Texto Puntaje, eso es el siguiente paso).
using UnityEngine;
using TMPro;

// Administra el estado general de la partida. Por ahora, solo el puntaje.
public class GameManager : MonoBehaviour
{
    // Guardamos una única referencia estática a este GameManager (patrón "Singleton").
    // Así, cualquier otro script puede sumar puntos con GameManager.instancia.SumarPuntos(...)
    // sin que nosotros tengamos que arrastrar una referencia a mano en cada Inspector,
    // como sí hicimos con bulletPrefab o firePoint.
    public static GameManager instancia;

    [Header("Puntaje")]
    public TMP_Text textoPuntaje;

    private int puntaje = 0;

    void Awake()
    {
        instancia = this;
    }

    void Start()
    {
        ActualizarTextoPuntaje();
    }

    public void SumarPuntos(int cantidad)
    {
        puntaje += cantidad;
        ActualizarTextoPuntaje();
    }

    void ActualizarTextoPuntaje()
    {
        textoPuntaje.text = "Puntaje: " + puntaje;
    }
}

5.2 Crear el marcador de puntaje en pantalla

  1. En la Hierarchy, clic derecho > UI > Text - TextMeshPro. Si es la primera vez que usas TextMeshPro en este proyecto, Unity va a ofrecer Import TMP Essentials — acéptalo (es un paso único). Esto crea automáticamente un Canvas y un EventSystem además del texto.
  2. Renombra el texto a TextoPuntaje.
  3. En su Rect Transform, ubícalo en la esquina superior izquierda (podés usar el selector de Anchor Presets y elegir la opción superior-izquierda).
  4. En el componente TextMeshPro - Text, escribe Puntaje: 0 como texto de prueba, y ajusta el tamaño de fuente para que se lea bien.

Hierarchy con Canvas > TextoPuntaje, e Inspector del texto

  1. Selecciona el GameObject GameManager y arrastra TextoPuntaje (desde la Hierarchy) al campo Texto Puntaje del componente Game Manager.

Inspector de GameManager con Texto Puntaje asignado

5.3 Definir cuántos puntos vale cada enemigo

using UnityEngine;

// Componente simple que solo guarda cuántos puntos vale destruir a este enemigo.
// Lo agregamos tanto a EnemyChaser como a EnemyShooter, para que la bala pueda
// preguntarlo sin necesitar saber de qué tipo de enemigo se trata.
public class EnemyPoints : MonoBehaviour
{
    public int valorDePuntos = 10;
}
  1. Abre el prefab EnemyChaser (doble clic en Assets/Prefabs/EnemyChaser) y arrastra el script EnemyPoints.cs sobre él. Dejalo en 10 puntos.
  2. Abre el prefab EnemyShooter y agrégale el mismo componente Enemy Points. Como este enemigo es más peligroso (dispara), puedes subirle el valor a 20.

Note

Al ser un componente separado (en vez de escribir el valor de puntos dentro de EnemyChaser.cs y EnemyShooter.cs por separado), la bala va a poder preguntar "¿cuántos puntos vale este enemigo?" sin importarle de qué tipo es.

5.4 Preparar la bala del jugador para impactar enemigos

  1. Abre el prefab Bullet (doble clic en Assets/Prefabs/Bullet).
  2. Add Component > Circle Collider 2D, con Is Trigger activado (igual que en la nave y los enemigos: queremos detectar el impacto, no que rebote físicamente).

El script Bullet.cs ya está actualizado con la lógica del impacto:

using UnityEngine;

// Controla el comportamiento de cada bala disparada por el jugador:
// se mueve hacia arriba y se destruye sola después de un tiempo.
public class Bullet : MonoBehaviour
{
    [Header("Movimiento")]
    public float moveSpeed = 12f;

    [Header("Duración")]
    // Cuántos segundos vive la bala antes de autodestruirse.
    // Esto evita que queden balas acumulándose fuera de la pantalla para siempre,
    // lo que iría gastando memoria de a poco.
    public float tiempoDeVida = 2f;

    void Start()
    {
        // Destroy(gameObject, segundos) programa la destrucción de este GameObject
        // luego de que pase esa cantidad de segundos.
        Destroy(gameObject, tiempoDeVida);
    }

    void Update()
    {
        // transform.Translate mueve el objeto en la dirección indicada.
        // Vector3.up equivale a (0, 1, 0): hacia arriba de la pantalla.
        transform.Translate(Vector3.up * moveSpeed * Time.deltaTime);
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Enemy"))
        {
            // Le preguntamos al enemigo cuántos puntos vale (componente EnemyPoints)
            // y se los sumamos al puntaje a través del GameManager.
            EnemyPoints puntosDelEnemigo = other.GetComponent<EnemyPoints>();
            if (puntosDelEnemigo != null)
            {
                GameManager.instancia.SumarPuntos(puntosDelEnemigo.valorDePuntos);
            }

            Destroy(other.gameObject);
            Destroy(gameObject);
        }
    }
}

Inspector del prefab Bullet con Circle Collider 2D (Is Trigger activado)

5.5 Probar todo junto

Presiona Play, dispara a los enemigos que van apareciendo, y confirma que:

  • Al impactar a un enemigo, tanto la bala como el enemigo desaparecen.
  • El marcador de puntaje sube (10 puntos por EnemyChaser, 20 por EnemyShooter).

Jugando en modo Play: marcador de puntaje después de destruir un enemigo

Checkpoint ✅

Al terminar este módulo, cada vez que una bala del jugador toque a un enemigo, ambos deberían desaparecer y el puntaje en pantalla debería aumentar según el tipo de enemigo destruido.