
I found a project on GitHub called PythonPlantsVsZombies. It's a clone of the legendary "Plants vs. Zombies" in Pygame: with animations, different zombie types, and levels defined via JSON. But once you peek under the hood, you start to feel sorry for the zombies. At least they don't have to maintain this code.
Let's dissect this engineering masterpiece.
1️⃣ Hell of
if-elif or "Factory on Crutches"In the file
source/state/level.py lives the method addPlant. When you plant a plant on a cell, the engine launches an interrogation with 19 branches of elif. "Are you a sunflower? No? Maybe a peashooter? Still no? Then perhaps a cherry bomb?"
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])
# ... and so on 17 more timesWant to add a new type of sunflower? Go to the middle of the file and append another:
elif self.plant_name == c.SUNSHROOM:
new_plant = plant.SunShroom(x, y, self.sun_group)This is a classic anti-pattern. In a normal world, we'd use a class registry or a mapping. One dictionary turns this disgrace into two elegant lines.
2️⃣ Synchronizing Lists — A Path to Schizophrenia
In
source/component/menubar.py, plant data (names, costs, cooldowns) is scattered across four independent lists. All of them must be strictly the same length and in strict order.
Off by one index in plant_sun_list? Congratulations, now your peashooter costs as much as a cherry bomb, and the cherry bomb is free.
We have
dataclasses, dictionaries, OOP, after all. Group related data into objects, otherwise debugging becomes hell.3️⃣ Global Side Effects.
In
source/tool.py, Pygame initialization and window creation (SCREEN) happen right at the module level. What's the problem: You can't simply import a constant or helper function from this file into tests without initializing the entire graphics core. This kills the possibility of unit testing. Logic should be separated from "hardware".
4️⃣ Smart "Brain" with Dumb Objects
Instead of using polymorphism (where each plant knows how to attack), the main class
Level manually checks string names: if plant.name == c.THREEPEASHOOTER, and decides where to shoot. This makes plant classes mere decorations with images, and the game logic an unmanageable monolith.Verdict:
The project is cool as a demo and a way to tinker with Pygame. But if you bring such architectural approach to a real project, you'll be eaten faster than zombies eat a walnut on the first line.
🎓 What we learn:
1. Don't make giant
if-else chains where polymorphism works.2. Group related data into objects or dictionaries.
3. If your code has the phrase "the index in this list corresponds to the index in that list" — delete everything and rewrite.
4. Resources (graphics/sound) should be loaded lazily (Lazy Loading), not "all at once" when importing a module.
#roasting_code
Comments
0No comments yet.