Saltar al contenido
Volver al inicio 100 Días de Código en Python — Día 95: Proyecto de portafolio — Space Invaders con turtle

100 Días de Código en Python — Día 95: Proyecto de portafolio — Space Invaders con turtle

Nivel: Grado décimo Área: Tecnología e Informática Modalidad: Tutorial práctico Fuente: Curso "100 Days of Code: The Complete Python Pro Bootcamp" (Angela Yu, App Brewery). Contenido del Día 95, proyecto de portafolio profesional (categoría Game).

Este tutorial adapta pedagógicamente el Día 95. La sección 📝 Contenido original del curso proviene del único archivo de la carpeta: dia95-tarea14.md (enunciado y pregunta de reflexión, en inglés; aquí traducido). El curso no ofrece guía ni solución, y este tutorial no entrega el juego terminado. Todo lo que no está en ese archivo (especificación, movimiento de la flota como unidad, proyectiles, barreras con "vida", organización con clases, retos 🟢🟡🟠🔴, proyecto extra y la etapa 14 de Mi Portafolio Profesional) es creación de esta adaptación.

Nota sobre las verificaciones: el 28 de septiembre de 2026, con Python 3.14, se ejecutaron las funciones puras de las secciones 4 y 5: una flota de 5 alienígenas entre x = −100 y x = 100 avanza 18 pasos a la derecha, en el paso 19 baja 20 píxeles y cambia de dirección; una versión con error en la que cada alienígena revisa su propio borde rompe la formación ([(280, 180), (240, 200)]). La parte gráfica con turtle se describe a partir de los Días 20–23 y no se ejecutó en pantalla.


Tabla de contenidos

  1. La tarea: Space Invaders
  2. Especificar antes de programar
  3. 📖 Organizar el juego con clases (lo que ya sabes)
  4. 📖 La flota se mueve como un solo bloque
  5. 📖 Disparos, impactos y barreras
  6. 🚀 Proyecto del día: construcción por versiones
  7. 🌟 Proyecto extra: Defensores del páramo
  8. 🏗️ Mi Portafolio Profesional — Etapa 14
  9. 🧩 Comprueba lo aprendido
  10. 🤖 Programar con apoyo de IA
  11. 🛠️ Observaciones sobre el material original
  12. 📋 Matriz de trazabilidad
  13. 📦 Evidencias de aprendizaje del Día 95

1. La tarea: Space Invaders

(Fuente: dia95-tarea14.md)

📝 Contenido original del curso

Usando Python Turtle, construye el clásico juego de disparos Space Invaders. (El enunciado enlaza la página de Wikipedia del juego.)

Tu nave espacial puede moverse a la izquierda y a la derecha y puede disparar a algunas naves alienígenas. Cada segundo, los alienígenas se acercan a tu nave. Cuando los alienígenas tocan tu nave, se acaba el juego (game over). Normalmente hay algunas barreras entre tú y los alienígenas que te ofrecen posiciones defensivas.

Puedes jugarlo en elgoog.im/space-invaders.

Pregunta de la tarea — Momento de reflexión: cómo abordaste el proyecto; qué fue difícil y qué fácil; cómo mejorarías; tu mayor aprendizaje; qué harías distinto.

Prerequisitos: turtle, eventos de teclado y tracer/update (Días 18–20); herencia (Día 21); Pong, Turtle Crossing y Breakout (Días 22, 23 y 87); listas y comprensión de listas (Días 4 y 26).


2. Especificar antes de programar

(Sección creada para esta adaptación, aplicando el método que el curso pidió en el Día 87.)

🔍 Antes de programar

Juega 5 minutos y escribe la especificación. Ejemplo (el tuyo puede ser distinto):

Texto
OBJETOS: Nave, Alien (muchos, en formación), Bala (de la nave), Bala enemiga,
         Barrera (varios bloques), Marcador
REGLAS:
  - La nave se mueve ← → sin salir de la pantalla y dispara con espacio.
  - Solo una bala de la nave en pantalla a la vez (como en el original).
  - La flota se mueve de lado a lado; al tocar un borde, TODA baja y cambia de dirección.
  - Bala que toca un alien: ambos desaparecen, suma puntos.
  - Los aliens disparan al azar hacia abajo.
  - Bala (de cualquiera) que toca una barrera: la barrera pierde un "trozo".
  - Game over si una bala enemiga toca la nave (y se acaban las vidas)
    o si un alien llega a la altura de la nave.
  - Victoria (o siguiente nivel) si no quedan aliens.

Lista de tareas sugerida: ventana y ciclo → nave → disparo → flota estática → flota en movimiento → impactos → disparos enemigos → barreras → vidas y marcador → fin del juego.

💡 Compara con el Breakout (Día 87): la bala es como la pelota (pero va en línea recta y desaparece); los alienígenas son como los ladrillos (pero se mueven). Reutiliza lo que puedas.


3. 📖 Organizar el juego con clases (lo que ya sabes)

(Sección creada para esta adaptación.)

Clase Hereda de Responsabilidad
Nave Turtle Moverse con límites, crear balas
Bala Turtle Avanzar en línea recta; saber si salió de la pantalla
Alien Turtle Su forma, color y puntos
Flota — (contiene una lista de Alien) Moverse como bloque, elegir quién dispara, saber si quedan aliens
Barrera — (lista de bloques pequeños) Perder bloques al recibir impactos
Marcador Turtle Puntos, vidas, mensajes

Una idea importante: Flota no hereda de Turtle, sino que contiene muchos. Eso se llama composición ("una flota tiene aliens") y es distinto de la herencia ("un alien es una tortuga"). Pregúntate con cada clase: ¿"es un" o "tiene un"?

Formas personalizadas: turtle permite registrar una imagen .gif como forma (screen.addshape("alien.gif") y alien.shape("alien.gif")). Las imágenes GIF no rotan con la tortuga, lo que aquí no importa. Usa imágenes propias o con licencia libre.


4. 📖 La flota se mueve como un solo bloque

(Sección creada para esta adaptación. Función verificada.)

🎯 Objetivo de aprendizaje

Mover un grupo de objetos de forma coordinada, tomando decisiones sobre el grupo, no sobre cada objeto por separado.

📖 Explicación conceptual

Si cada alienígena revisara su propio borde, el de la derecha bajaría y los demás seguirían avanzando: la formación se deshace. Verificado con una versión con error: dos aliens en x = 280 y x = 230 terminan en [(280, 180), (240, 200)], a alturas distintas.

La decisión correcta se toma para toda la flota: si el alien que está más a la derecha (o más a la izquierda) va a salirse, todos bajan y todos cambian de dirección.

🔎 Ejemplo explicado

Python
BORDE = 280

def mover_flota(posiciones, direccion, paso=10, bajada=20):
    if not posiciones:
        return posiciones, direccion
    xs = [x for x, _ in posiciones]
    if max(xs) + paso * direccion > BORDE or min(xs) + paso * direccion < -BORDE:
        return [(x, y - bajada) for x, y in posiciones], -direccion
    return [(x + paso * direccion, y) for x, y in posiciones], direccion
  • Trabaja con tuplas de posiciones, no con tortugas: se prueba sin ventana. En el juego, aplicarías las nuevas posiciones con alien.goto(x, y).
  • direccion es 1 (derecha) o -1 (izquierda): multiplicar por ella evita escribir dos casos.
  • Se revisa la próxima posición (max(xs) + paso * direccion) para no salirse ni un paso.
  • if not posiciones evita el error de max() con una lista vacía (cuando no quedan aliens).

Verificado: 5 aliens entre −100 y 100 avanzan 18 pasos; en el paso 19 bajan de y = 200 a y = 180 y la dirección pasa a −1; en el siguiente paso el de la derecha va de 280 a 270.

¿"Cada segundo"?

El enunciado dice que los aliens se acercan cada segundo, pero el ciclo del juego se repite muchas veces por segundo (para que la nave y las balas se muevan suave). Solución: mover la flota solo cada cierto número de cuadros, o con un temporizador aparte (screen.ontimer(mover, 1000)). En el original, la flota acelera a medida que quedan menos aliens: ¿cómo lo harías?


5. 📖 Disparos, impactos y barreras

(Sección creada para esta adaptación.)

Balas

  • Una bala a la vez: si ya hay una bala de la nave en pantalla, la barra espaciadora no hace nada. Esto hace el juego más estratégico y simplifica el código.
  • Balas que salen de la pantalla: ocúltalas y quítalas de la lista (o reutilízalas). Si solo las ocultas, la lista crece sin fin y el juego se vuelve lento.

Impactos

Usa la idea de colisión rectangular del Breakout (Día 87): comparar la distancia en cada eje con la suma de los "medios tamaños". Y aplica la regla de oro: no eliminar de una lista mientras la recorres; recorre una copia o marca los eliminados y bórralos después.

Barreras con "vida"

Dos enfoques:

Enfoque Cómo Ventaja Desventaja
Barrera con contador Un solo objeto con vida = 5; cambia de color al recibir impactos Simple No se ve el "hueco" del impacto
Barrera de bloques Muchos cuadritos pequeños; cada impacto borra uno Se parece al original Muchas colisiones que revisar (más lento)

Alcanzar la nave

Python
def alcanzo_nave(posiciones, y_nave=-250, margen=20):
    return any(y <= y_nave + margen for _, y in posiciones)

any(...) devuelve True si al menos un alien cumple la condición (verificado: un alien en y = −240 → True; en y = 0 → False).

⚠️ Errores frecuentes

Error Qué ocurre Solución
Cada alien revisa su borde La formación se deshace Decisión sobre el grupo (sección 4)
max() de una lista vacía ValueError al matar al último alien Comprueba si quedan aliens
Balas infinitas El juego se vuelve lento Límite de balas y eliminar las que salen
Una bala destruye varios aliens Atraviesa la fila Al primer impacto, la bala desaparece (break)
La flota se mueve demasiado rápido Se mueve en cada cuadro Contador de cuadros o ontimer
screen.onkey sin screen.listen() Las teclas no responden screen.listen() antes del ciclo

6. 🚀 Proyecto del día: construcción por versiones

(Desarrolla la tarea dia95-tarea14.md. Las versiones siguen la lista de tareas de la sección 2.)

Problema

Construir Space Invaders con Python turtle.

Contexto

Continúa la "semana de juegos clásicos" (Día 87): cada grupo presenta un segundo juego, esta vez con muchos objetos en movimiento.

Objetivo

Un Space Invaders jugable, con flota en formación, disparos de ambos lados, barreras, vidas y marcador.

Requisitos funcionales

  1. Nave que se mueve ← → con límites y dispara con espacio.
  2. Flota de al menos 3 filas × 8 columnas que se mueve en bloque y baja al tocar un borde.
  3. Impactos de balas en aliens (con puntos) y en barreras.
  4. Game over si los aliens alcanzan la nave o si se acaban las vidas; victoria si no quedan aliens.

Restricciones técnicas

  • Clases en archivos separados (nave.py, flota.py, barrera.py, marcador.py).
  • Movimiento de la flota y colisiones en funciones puras probadas.
  • Sin copiar un tutorial de Space Invaders (mismo principio del Día 87).

Planificación

La especificación de la sección 2 es tu plan. Añade: probar cada tarea antes de marcarla; corregir; mejorar con los retos.

Construcción paso a paso

  • Versión 1 — Nave: ventana, ciclo y nave con límites.
  • Versión 2 — Disparo: una bala a la vez, que desaparece al salir.
  • Versión 3 — Flota: formación estática; luego, movimiento en bloque.
  • Versión 4 — Impactos: balas contra aliens, puntos.
  • Versión 5 — Contraataque: disparos enemigos al azar (random.choice de los aliens de la fila inferior de cada columna), vidas.
  • Versión 6 — Barreras.
  • Versión final: fin del juego, reinicio, README.md con GIF y diario.

Pruebas

# Caso Resultado esperado
1 mover_flota con 5 aliens desde −100…100 hacia la derecha 18 pasos a la derecha; en el 19, bajan 20 y cambia la dirección
2 mover_flota([], 1) ([], 1) sin error
3 alcanzo_nave([(0, -240)]) True
4 Pulsar espacio 10 veces rápido Solo una bala en pantalla
5 Matar al último alien Victoria, sin errores
6 Barrera que recibe 5 impactos (o todos sus bloques) Desaparece
7 Jugar 3 minutos El juego no se vuelve más lento con el tiempo

🧪 Prueba y depuración

Python
for alien in aliens:
    if alien.xcor() > 280 or alien.xcor() < -280:
        direccion *= -1
        alien.sety(alien.ycor() - 20)
    alien.setx(alien.xcor() + 10 * direccion)

Encuentra tres problemas: solo baja el alien que tocó el borde (la formación se rompe); la dirección puede cambiar varias veces en la misma vuelta si varios aliens están en el borde; y los aliens ya recorridos se movieron con la dirección anterior.

⭐ Extensión del proyecto

  • 🟢 Reto 1 — Aplicación: la flota acelera a medida que quedan menos aliens.
  • 🟡 Reto 2 — Ampliación: la nave misteriosa (OVNI) que cruza la parte superior de vez en cuando y da puntos al azar.
  • 🟠 Reto 3 — Desafío: barreras de bloques que se "desmoronan" de forma realista (el bloque golpeado y, a veces, un vecino).
  • 🔴 Reto 4 — Pensamiento computacional: niveles con formaciones distintas leídas desde archivos de texto, y una dificultad que se ajusta al jugador (si pierde rápido, el siguiente intento es un poco más fácil). Diseña la regla de ajuste y justifica por qué es justa.

7. 🌟 Proyecto extra: Defensores del páramo

(Proyecto creado para esta adaptación; no existe en el curso original.)

Situación

Los páramos colombianos producen buena parte del agua que llega a muchas ciudades. El grupo ecológico quiere un juego que muestre sus amenazas: desde arriba descienden "amenazas" (incendios, basura, ganadería no controlada, minería ilegal) hacia los frailejones de la parte inferior.

Requisitos

  1. Reutiliza la estructura de tu Space Invaders: las amenazas bajan en formación.
  2. El jugador elige la "herramienta" adecuada para cada amenaza (por ejemplo, 1 = agua, 2 = recolección, 3 = vigilancia), con disparos de color distinto; solo la correcta elimina la amenaza.
  3. Al final, una pantalla con un dato real sobre cada amenaza, con su fuente (investiga en fuentes confiables).

Decisiones que debes tomar (y justificar)

  • ¿Cómo muestras qué herramienta sirve para qué amenaza sin que el juego sea solo adivinar?
  • ¿Cómo evitas que el juego trivialice un problema serio?

Casos de prueba

  • Herramienta incorrecta: la amenaza sigue.
  • Un frailejón alcanzado desaparece; si se pierden todos, el juego termina.

8. 🏗️ Mi Portafolio Profesional — Etapa 14

(Proyecto integrador creado para esta adaptación; etapas anteriores en los Días 82 a 94.)

Etapa 14 (hoy):

  1. Repositorio con PLAN.md (especificación y lista de tareas), las clases, las pruebas de las funciones puras y un GIF.
  2. En el README.md, un diagrama simple de las clases con sus relaciones "es un" / "tiene un".
  3. DIARIO.md del Día 95 y ficha en proyectos.json.
  4. Comparación: en tu diario, compara el Breakout (Día 87) con este juego. ¿Qué código reutilizaste? ¿Qué hiciste mejor esta vez?

9. 🧩 Comprueba lo aprendido

Conceptuales

  1. ¿Qué diferencia hay entre herencia y composición? Da un ejemplo de cada una en este juego.
  2. ¿Por qué la decisión de bajar debe tomarse para toda la flota?
  3. ¿Por qué hay que eliminar de la lista las balas que salen de la pantalla?
  4. ¿Qué hace any()?

Análisis de código

Python
xs = [x for x, _ in posiciones]

¿Qué contiene xs? ¿Qué significa el _?

Predicción

Con BORDE = 280, una flota cuyo alien más a la derecha está en x = 275 y direccion = 1, paso = 10: ¿qué hace mover_flota?

Depuración

"Cuando elimino al último alien, el juego se cierra con ValueError: max() arg is an empty sequence." ¿Dónde y cómo lo corriges?

Modificación

Cambia mover_flota para que el paso aumente cuando quedan menos de 10 aliens.

Creación

Escribe aliens_que_pueden_disparar(posiciones) que devuelva, para cada columna (misma x), solo el alien de más abajo.


10. 🤖 Programar con apoyo de IA

Ciclo de trabajo: formula el problema → inténtalo tú primero → consulta a la IA sobre un punto concreto → lee y entiende → prueba → compara con la documentación oficial → modifica → explica con tus palabras.

Actividad 1 — Conceptos, no juegos. Pregunta a una IA "¿cuál es la diferencia entre herencia y composición en programación orientada a objetos?". Aplica la explicación a tus clases y justifica cada relación.

Actividad 2 — Revisión de rendimiento. Si tu juego se vuelve lento, describe (sin pegar todo el código) cuántos objetos hay y cómo revisas colisiones. Pide ideas y mide con time.perf_counter() si mejoran.

Actividad 3 — Documentación. Pregunta cómo usar imágenes GIF como formas en turtle. Comprueba en la documentación oficial (register_shape/addshape) qué formatos admite.

Declara el uso: sección "Uso de IA" en el README.md.


11. 🛠️ Observaciones sobre el material original

Archivo Observación Tratamiento
dia95-tarea14.md "Cada segundo los aliens se acercan" no encaja con un ciclo de muchos cuadros por segundo Sección 4: contador de cuadros u ontimer
dia95-tarea14.md No menciona que la flota debe moverse como bloque Sección 4, con el error verificado
dia95-tarea14.md Las barreras son opcionales ("usually") Versión 6 y reto 3
dia95-tarea14.md Enlaza una versión jugable en un sitio espejo (elgoog.im) Se conserva como referencia

12. 📋 Matriz de trazabilidad

Contenido original Archivo de origen Concepto desarrollado Ejercicio original Reto adicional Proyecto relacionado
Space Invaders con Python Turtle dia95-tarea14.md Secciones 2 y 3 Juego Space Invaders Retos 2 y 4 Secciones 6 y 8
Nave que se mueve a los lados y dispara dia95-tarea14.md Sección 5 Juego Space Invaders — Sección 6
Aliens que se acercan cada segundo; game over al tocar la nave dia95-tarea14.md Secciones 4 y 5 Juego Space Invaders Reto 1 Sección 6
Barreras defensivas dia95-tarea14.md Sección 5 Juego Space Invaders Reto 3 Sección 6
Momento de reflexión dia95-tarea14.md Sección 6 (versión final) Pregunta de reflexión — Sección 8
(No existe en el curso original) — Composición, movimiento en bloque — Defensores del páramo Sección 7

13. 📦 Evidencias de aprendizaje del Día 95

  • PLAN.md con la especificación y la lista de tareas.
  • El juego funcionando (GIF o video con victoria y game over).
  • Pruebas de mover_flota, colisiones y alcanzo_nave.
  • Diagrama de clases y comparación con el Breakout.
  • DIARIO.md del Día 95 y ficha en el portafolio.
  • Cuaderno de errores: formación que se deshace, max() de lista vacía, balas infinitas, bala que atraviesa varios aliens, flota demasiado rápida, teclas sin listen().