Encontré en GitHub el proyecto PythonPlantsVsZombies. Es un clon del legendario «Plantas vs. Zombis» en Pygame: con animaciones, diferentes tipos de zombis y niveles mediante JSON. Pero en cuanto miras «bajo el capó», empiezas a compadecer a los zombis. Al menos ellos no tienen que mantener este código.

Diseccionemos esta obra maestra de ingeniería.

1️⃣ Infierno de if-elif o «Fábrica con muletas»
En el archivo source/state/level.py vive el método addPlant. Cuando plantas una planta en una celda, el motor inicia un interrogatorio de 19 ramas elif.

«¿Eres un girasol? ¿No? ¿Y tal vez un lanzaguisantes? ¿Tampoco? Entonces, ¿quizás una cereza?»


if self.plant_name == c.SUNFLOWER:
new_plant = plant.SunFlower(x, y, self.sun_group)
elif self.plant_name == c.PEASHOOTER:
new_plant = plant.PeaShooter(x, y, self.bullet_groups[map_y])
# ... y así 17 veces más


¿Quieres añadir un nuevo tipo de girasol? Ve al medio del archivo y escribe otro:
elif self.plant_name == c.SUNSHROOM:
new_plant = plant.SunShroom(x, y, self.sun_group)


Esto es un antipatrón clásico. En un mundo normal usaríamos un registro de clases o un mapeo. Un solo diccionario — y esta vergüenza se convierte en dos elegantes líneas.

2️⃣ Sincronización de listas — camino a la esquizofrenia
En source/component/menubar.py, los datos de las plantas (nombres, costo, enfriamiento) están dispersos en cuatro listas independientes.
Todas deben tener estrictamente la misma longitud y estrictamente el mismo orden.
¿Te equivocaste en un índice en plant_sun_list? Felicidades, ahora tu lanzaguisantes cuesta como una cereza, y la cereza es gratis.

Tenemos dataclasses, diccionarios, POO, al fin y al cabo. Agrupa los datos relacionados en objetos, si no, la depuración se convertirá en un infierno.

3️⃣ Efectos secundarios globales.
En source/tool.py, la inicialización de Pygame y la creación de la ventana (SCREEN) ocurren directamente a nivel de módulo.
El problema: No puedes simplemente importar una constante o función auxiliar de este archivo para pruebas sin inicializar todo el núcleo gráfico. Esto mata la posibilidad de pruebas unitarias. La lógica debe estar separada del «hardware».

4️⃣ «Cerebro» inteligente con objetos tontos
En lugar de usar polimorfismo (donde cada planta sabe cómo atacar), la clase principal Level verifica manualmente los nombres de las cadenas: if plant.name == c.THREEPEASHOOTER, y decide por sí misma hacia dónde disparar. Esto convierte a las clases de plantas en meras decoraciones con imágenes, y la lógica del juego en un monolito inmanejable.

Veredicto:
El proyecto es genial como demo y para experimentar con Pygame. Pero si llegas con este enfoque arquitectónico a un proyecto serio, te devorarán más rápido de lo que los zombis devoran una nuez en la primera línea.

🎓 Qué aprendemos:
1. No hagas cadenas gigantes de if-else donde funciona el polimorfismo.
2. Agrupa datos relacionados en objetos o diccionarios.
3. Si en tu código aparece la frase «el índice en esta lista corresponde al índice en esa lista», bórralo todo y reescribe.
4. Los recursos (gráficos/sonido) deben cargarse de forma perezosa (Lazy Loading), no «todo y de inmediato» al importar el módulo.

#asando_código