Módulo 3 — Física de Unity: lluvia de meteoritos (20 min)¶
¿Qué vamos a lograr?¶
Hasta ahora, todo lo que se mueve en el juego (la nave, las balas) lo movimos "a mano":
en cada frame, nosotros calculamos la nueva posición con código
(transform.position, transform.Translate). Eso se llama movimiento cinemático: el
código manda, la física no interviene para nada.
En este módulo vamos a ver la otra forma de mover objetos en Unity: dejar que el motor de físicas se encargue. Cada cierto tiempo va a caer un meteorito desde arriba, con gravedad real, y si dos meteoritos se chocan entre sí, van a rebotar y desviarse solos — sin que nosotros programemos ni una línea para el rebote. Eso es lo que hace un Rigidbody2D.
3.1 Conceptos: Rigidbody2D y Collider2D¶
Dos componentes de Unity que trabajan siempre juntos:
- Rigidbody2D: le dice a Unity "este objeto debe obedecer las leyes de la física" (gravedad, fuerzas, choques). Tiene un Body Type:
Dynamic: el motor de físicas lo controla por completo (cae, choca, rebota). Es el que vamos a usar para los meteoritos.Kinematic: se mueve solo si nosotros lo movemos por código, pero sí puede detectar colisiones. Lo vamos a usar más adelante para la nave y los enemigos.Static: no se mueve nunca (paredes, límites del escenario).- Collider2D: define la "forma física" del objeto para detectar colisiones (no tiene por qué ser igual a la forma visual del sprite). Para los meteoritos, que son redondos, usamos un Circle Collider 2D.
Cuando dos objetos con Collider2D se tocan y ninguno tiene marcada la casilla
Is Trigger, Unity resuelve la colisión como algo físico de verdad: los objetos se
empujan y rebotan entre sí. Esa casilla va a ser clave más adelante (Módulo 5), cuando
usemos colliders para detectar golpes por código en vez de dejar que reboten.
3.2 Crear el prefab del meteorito¶
- En la Hierarchy, clic derecho > 2D Object > Sprites > Square. Renómbralo a
Meteor. - En el Sprite Renderer, asígnale un sprite de la carpeta
Meteorsdel pack de Kenney. - Add Component > Rigidbody 2D. Dejalo en
Body Type: Dynamic(el que viene por defecto). Bájale el Gravity Scale a0.5para que caiga a una velocidad más controlada (con1cae más rápido de lo que se ve bien en pantalla). - Add Component > Circle Collider 2D. Dejalo con Is Trigger desactivado (sin marcar) — así los meteoritos van a rebotar físicamente entre ellos.
- Arrastra el script
Meteor.cs(ya escrito enMeteor.cs) sobre el GameObject.
using UnityEngine;
// Este script va sobre el prefab del meteorito.
// A diferencia de la nave y la bala, el meteorito NO se mueve por código:
// se mueve solo porque tiene un Rigidbody2D con gravedad, y Unity lo hace caer.
public class Meteor : MonoBehaviour
{
void Start()
{
// Le damos una rotación inicial al azar (grados por segundo).
// Como es un Rigidbody2D, con solo fijar este valor una vez acá, Unity se encarga
// de ir rotando el objeto solo en cada frame, sin que nosotros escribamos más código.
Rigidbody2D rb = GetComponent<Rigidbody2D>();
rb.angularVelocity = Random.Range(-90f, 90f);
}
// OnBecameInvisible() se llama automáticamente cuando el Sprite Renderer de este objeto
// deja de estar dentro de la vista de cualquier cámara. Es otra forma de "limpiar"
// objetos que ya no se necesitan, distinta a las que usamos en la nave y en la bala.
void OnBecameInvisible()
{
Destroy(gameObject);
}
// El Collider2D del meteorito NO es un trigger (así los meteoritos chocan físicamente
// entre ellos). Pero el Collider2D de la nave sí va a ser un trigger (sección 3.3) —
// y como con que UNO de los dos sea trigger alcanza, este choque en particular se
// avisa acá, con OnTriggerEnter2D, en vez de con OnCollisionEnter2D.
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
// Todavía no armamos el sistema de vida (eso es el Módulo 6), así que por
// ahora el impacto destruye la nave directamente: es una muerte instantánea,
// sin importar cuánta vida tuviera. Más adelante vamos a cambiar esta línea
// por una llamada al sistema de vida, para restarle toda la vida de una vez.
Destroy(other.gameObject);
Destroy(gameObject);
}
}
}
- Arrastra el GameObject
MeteorhastaAssets/Prefabspara convertirlo en prefab, y borra el que quedó en la Hierarchy.
3.3 Preparar la nave para recibir el impacto¶
Para que el meteorito pueda "darse cuenta" de que tocó a la nave, la nave también
necesita un Collider2D. Y para que la detección funcione de forma confiable, también le
agregamos un Rigidbody2D (la regla general en Unity es: al menos uno de los dos
objetos que chocan necesita un Rigidbody2D — se lo damos a los dos para no tener que
acordarnos de esa regla cada vez).
- Selecciona el GameObject
Player. - Arriba del Inspector, en el campo Tag, cambia
UntaggedporPlayer(es una etiqueta que Unity ya trae creada). Así es como el script del meteorito reconoce a la nave. - Add Component > Circle Collider 2D. Esta vez sí marca la casilla Is Trigger — la nave no debe rebotar como un objeto físico, solo detectar el impacto por código.
- Add Component > Rigidbody 2D. Cambia el Body Type a
Kinematic(así seguimos moviendo la nave nosotros mismos, por código, como ya hacePlayerController, pero ahora también participa en la detección de colisiones).
Opcional
Si quieres que los meteoritos reboten de forma más "elástica" al chocar entre sí,
crea un Physics Material 2D (clic derecho en Assets > Create > 2D > Physics
Material 2D), súbele el valor Bounciness a algo como 0.4, y asígnalo en el
campo Material del Circle Collider 2D del meteorito.
3.4 Crear el spawner de meteoritos¶
Un spawner es un GameObject que no se ve en pantalla, cuyo único trabajo es ir creando otros GameObjects con el tiempo. Vamos a usar este mismo patrón más adelante para los enemigos.
- En la Hierarchy, clic derecho > Create Empty. Renómbralo a
MeteorSpawner. - Arrastra el script
MeteorSpawner.cssobre él.
using UnityEngine;
// Crea meteoritos nuevos cada cierto tiempo, en una posición X al azar,
// justo por encima del borde superior de la pantalla.
public class MeteorSpawner : MonoBehaviour
{
[Header("Meteoritos")]
public GameObject meteorPrefab;
// Cada cuántos segundos cae un meteorito nuevo.
public float intervaloEntreMeteoritos = 3f;
// Qué tan fuerte puede ser el empujón lateral inicial (hacia la izquierda o la
// derecha). Con esto los meteoritos no caen todos derechito hacia abajo.
public float velocidadLateralMaxima = 2f;
private float minX, maxX, topY;
void Start()
{
CalcularLimitesDePantalla();
// InvokeRepeating llama a un método una y otra vez, cada cierto intervalo de tiempo,
// sin que nosotros tengamos que llevar la cuenta del tiempo a mano en Update().
InvokeRepeating(nameof(CrearMeteorito), intervaloEntreMeteoritos, intervaloEntreMeteoritos);
}
void CalcularLimitesDePantalla()
{
Camera camara = Camera.main;
Vector3 esquinaInferior = camara.ViewportToWorldPoint(new Vector3(0f, 0f, 0f));
Vector3 esquinaSuperior = camara.ViewportToWorldPoint(new Vector3(1f, 1f, 0f));
minX = esquinaInferior.x;
maxX = esquinaSuperior.x;
topY = esquinaSuperior.y + 1f; // un poco arriba del borde, para que aparezca "cayendo"
}
void CrearMeteorito()
{
// Random.Range(min, max) devuelve un número al azar entre esos dos valores.
float posicionX = Random.Range(minX, maxX);
Vector3 posicionDeAparicion = new Vector3(posicionX, topY, 0f);
GameObject meteorito = Instantiate(meteorPrefab, posicionDeAparicion, Quaternion.identity);
// Le damos un empujón lateral al azar. La gravedad se encarga de acelerarlo hacia
// abajo, así que el resultado es una caída en ángulo (una curva), no una línea recta.
Rigidbody2D rb = meteorito.GetComponent<Rigidbody2D>();
float impulsoLateral = Random.Range(-velocidadLateralMaxima, velocidadLateralMaxima);
rb.linearVelocity = new Vector2(impulsoLateral, 0f);
}
}
- Arrastra el prefab
Meteor(desdeAssets/Prefabs) al campo Meteor Prefab del componenteMeteor Spawner. - Presiona Play y espera unos segundos — deberían empezar a caer meteoritos en ángulos ligeramente distintos, y si dos coinciden en el mismo lugar, deberían rebotar entre sí solos. Si uno toca la nave, la debería destruir al instante.
Checkpoint ✅¶
Al terminar este módulo deberían caer meteoritos solos, cada intervaloEntreMeteoritos
segundos, en trayectorias ligeramente distintas. Si dos se cruzan en el aire, la física
de Unity los debería desviar automáticamente, sin ningún código nuestro para ese rebote.
Y si uno toca la nave, la nave debería destruirse al instante.



