Módulo 1 — La nave del jugador (25 min)¶
¿Qué vamos a lograr?¶
Una nave en pantalla que se mueve con WASD o las flechas, sin poder salirse de la vista de la cámara.
1.1 Crear el GameObject de la nave¶
- En la ventana Hierarchy, clic derecho > 2D Object > Sprites > Square
(esto crea un GameObject con un
Sprite Rendererya listo). Renómbralo aPlayer. - En el Inspector, en el componente Sprite Renderer, cambia el campo Sprite por
tu nave (por ejemplo
playerShip1_blue). Como el juego es vertical y los sprites de Kenney ya apuntan hacia arriba de fábrica, no hace falta rotar nada. - Ubícala cerca del borde inferior de la pantalla (por ejemplo, posición
X = 0, Y = -3).
1.2 El script de movimiento¶
Este script ya está escrito y comentado línea por línea en
PlayerController.cs — solo hay
que copiarlo dentro de tu propio proyecto. (Este mismo script se va a ir completando en
el Módulo 2 con el disparo, así que ya lo dejamos con esa sección lista.)
using UnityEngine;
// Este script controla la nave del jugador: cómo se mueve por la pantalla y cómo dispara.
// Hay que arrastrarlo (o agregarlo con Add Component) sobre el GameObject "Player".
public class PlayerController : MonoBehaviour
{
[Header("Movimiento")]
// Qué tan rápido se mueve la nave (unidades por segundo).
// Al ser "public", este valor aparece en el Inspector y se puede ajustar sin tocar código.
public float moveSpeed = 8f;
// Un pequeño margen para que la nave no quede "cortada" justo en el borde de la pantalla.
public float edgePadding = 0.4f;
[Header("Disparo")]
// El prefab de la bala que vamos a crear cada vez que se dispara.
// Se asigna arrastrándolo desde Assets/Prefabs hasta este campo en el Inspector.
public GameObject bulletPrefab;
// El punto exacto de la nave desde donde "nace" cada bala (la punta de la nave).
public Transform firePoint;
// Cuántos segundos mínimo deben pasar entre un disparo y el siguiente.
public float fireRate = 0.3f;
// Estas variables guardan los límites de la pantalla (izquierda, derecha, abajo, arriba)
// en coordenadas del mundo del juego. Son "private" porque solo las usa este script.
private float minX, maxX, minY, maxY;
// Guarda el momento (según Time.time) en el que se vuelve a poder disparar.
private float proximoDisparoDisponible;
// Start() se ejecuta una sola vez, apenas empieza el juego.
// Acá aprovechamos para calcular los límites de la pantalla una única vez.
void Start()
{
CalcularLimitesDePantalla();
}
// Calcula en qué coordenadas del mundo empiezan y terminan los bordes de la cámara.
// Así, más abajo, podemos evitar que la nave se salga de la vista del jugador.
void CalcularLimitesDePantalla()
{
Camera camara = Camera.main;
// ViewportToWorldPoint convierte una posición "de pantalla" (0,0 = esquina inferior
// izquierda; 1,1 = esquina superior derecha) a una posición real del mundo del juego.
Vector3 esquinaInferior = camara.ViewportToWorldPoint(new Vector3(0f, 0f, 0f));
Vector3 esquinaSuperior = camara.ViewportToWorldPoint(new Vector3(1f, 1f, 0f));
// Guardamos los bordes, dejando un pequeño margen (edgePadding) hacia adentro.
minX = esquinaInferior.x + edgePadding;
maxX = esquinaSuperior.x - edgePadding;
minY = esquinaInferior.y + edgePadding;
maxY = esquinaSuperior.y - edgePadding;
}
// Update() se ejecuta una vez por cada frame (muchas veces por segundo).
// Separamos el trabajo en dos métodos (Mover y Disparar) para que quede ordenado.
void Update()
{
Mover();
Disparar();
}
void Mover()
{
// Input.GetAxisRaw("Horizontal") devuelve:
// -1 si se presiona A o la flecha izquierda
// +1 si se presiona D o la flecha derecha
// 0 si no se presiona nada
// Input.GetAxisRaw("Vertical") funciona igual, pero con W/S y las flechas arriba/abajo.
// Estos dos ejes ya vienen configurados en Unity por defecto: no hay que tocar nada más.
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
// Armamos un vector de dirección con esos dos valores.
// .normalized evita que la nave vaya más rápido al moverse en diagonal
// (sin esto, moverse en diagonal sumaría velocidad en X y en Y al mismo tiempo).
Vector3 direccion = new Vector3(horizontal, vertical, 0f).normalized;
// Calculamos la nueva posición: la posición actual, más la dirección,
// multiplicada por la velocidad y por Time.deltaTime.
// Time.deltaTime es el tiempo (en segundos) que pasó desde el último frame.
// Multiplicar por Time.deltaTime hace que la nave se mueva a la misma velocidad
// sin importar qué tan rápido o lento vaya el juego en cada computador.
Vector3 nuevaPosicion = transform.position + direccion * moveSpeed * Time.deltaTime;
// Mathf.Clamp "encierra" un valor entre un mínimo y un máximo.
// Acá lo usamos para que la nave nunca salga de los límites de la pantalla.
nuevaPosicion.x = Mathf.Clamp(nuevaPosicion.x, minX, maxX);
nuevaPosicion.y = Mathf.Clamp(nuevaPosicion.y, minY, maxY);
// Por último, aplicamos la nueva posición calculada a la nave.
transform.position = nuevaPosicion;
}
void Disparar()
{
// Input.GetKey (a diferencia de Input.GetKeyDown) devuelve true todo el rato que la
// tecla está apretada, por eso además controlamos un "tiempo de espera" (fireRate)
// para que no salga una bala nueva en cada frame.
if (Input.GetKey(KeyCode.Space) && Time.time >= proximoDisparoDisponible)
{
proximoDisparoDisponible = Time.time + fireRate;
// Instantiate crea una copia nueva del prefab bulletPrefab,
// ubicada en la posición y rotación de firePoint (la punta de la nave).
Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
}
}
}
Note
Los campos bulletPrefab y firePoint van a quedar vacíos en el Inspector hasta el
Módulo 2 — es normal, todavía no creamos esos objetos.
1.3 Conectar el script a la nave¶
- Selecciona el GameObject
Player. - Arrastra el archivo
PlayerController.csdesdeAssets/Scriptshasta el Inspector delPlayer(o usa Add Component > Player Controller). - Presiona Play y prueba moverte con WASD y con las flechas.
Checkpoint ✅¶
Al terminar este módulo se debería poder mover la nave libremente por la pantalla sin que se salga de los bordes, usando indistintamente WASD o las flechas.

