Нашел на просторах GitHub проект PythonPlantsVsZombies. Это клон легендарной «Растения против Зомби» на Pygame: с анимациями, разными типами зомби и уровнями через JSON. Но как только заглядываешь «под капот» — начинаешь сочувствовать зомби. Им хотя бы не нужно поддерживать этот код.

Давайте препарируем этот инженерный шедевр.

1️⃣ Ад из if-elif или «Фабрика на костылях»
В файле source/state/level.py живет метод addPlant. Когда вы сажаете растение на клетку, движок запускает допрос из 19 веток elif.

«Ты подсолнух? Нет? А может, горохострел? Тоже нет? Тогда, может, вишня?»


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])
# ... и так еще 17 раз


Хочешь добавить новый вид подсолнуха? Иди в середину файла и дописывай очередное:
elif self.plant_name == c.SUNSHROOM:
new_plant = plant.SunShroom(x, y, self.sun_group)


Это классический антипаттерн. В нормальном мире мы используем реестр классов или маппинг. Один словарь — и этот позор превращается в две элегантные строки.

2️⃣ Синхронизация списков — путь к шизофрении
В source/component/menubar.py данные о растениях (имена, стоимость, кулдаун) разбросаны по четырем независимым спискам.
Все они должны быть строго одной длины и в строгом порядке.
Ошибся на один индекс в plant_sun_list? Поздравляю, теперь твой горохострел стоит как вишня, а вишня бесплатная.

У нас есть dataclasses, есть словари, есть ООП, в конце концов. Группируйте связанные данные в объекты, иначе дебаг превратится в ад.

3️⃣ Глобальные побочные эффекты.
В source/tool.py инициализация Pygame и создание окна (SCREEN) происходит прямо на уровне модуля.
В чем проблема: Вы не можете просто импортировать константу или вспомогательную функцию из этого файла в тесты, не инициализировав всё графическое ядро. Это убивает возможность модульного тестирования. Логика должна быть отделена от «железа».

4️⃣ Умный «мозг» при глупых объектах
Вместо того чтобы использовать полиморфизм (где каждое растение само знает, как ему атаковать), основной класс Level вручную проверяет имена строк: if plant.name == c.THREEPEASHOOTER, и сам решает, куда стрелять. Это делает классы растений просто декорациями с картинками, а логику игры — неподъемным монолитом.

Вердикт:
Проект крутой как демка и способ потыкать Pygame. Но если вы придете с таким архитектурным подходом на нормальный проект — вас съедят быстрее, чем зомби съедают орех на первой линии.

🎓 Чему учимся:
1. Не делайте гигантские if-else цепочки там, где работает полиморфизм.
2. Группируйте связанные данные в объекты или словари.
3. Если у вас в коде есть фраза «индекс в этом списке соответствует индексу в том списке» — удаляйте всё и переписывайте.
4. Ресурсы (графика/звук) должны грузиться лениво (Lazy Loading), а не «всё и сразу» при импорте модуля.

#жарим_код