Найти тему
ZDG

Пишем Питона на Питоне #9: Главное меню и состояния игры

Предыдущие части: Геймплей, Есть ли у него душа, Организация ввода, View, Визуализация поля, Загрузка уровня, INI-файл, Пишем Питона на Питоне!

В этой части сделаем экран главного меню и немного усовершенствуем программу в целом.

Проект можно смотреть на github. Отныне я даю ссылку на конкретную ветку, в которой происходили изменения. То есть если в дальнейшем проект уйдёт вперёд, по этой ссылке всё останется как и было. Также вы можете скачать зип-архив.

Итак, у нас уже была играбельная версия Питона. Для главного меню я нарисовал кое-какую графику в редакторе Xara X:

Я подобрал более-менее подходящий шрифт из тех, что у меня есть, но к сожалению, в нём есть только латинские буквы. Поэтому надписи пока что будут только по-английски.

Все графические элементы (верхняя полоска, каждая строчка меню и указатель) были экспортированы из Xara X как отдельные картинки в формате PNG. Для пунктов меню было сделано по 2 варианта: тёмный (невыбранный) и светлый (выбранный).

Напомню, что мы придерживаемся шаблона проектирования MVC. В главном игровом режиме были контроллер, модель и представление. То же самое сделаем для режима главного меню.

Представление MainMenuView имеет понятие о следующих вещах:

  • Логотип
  • Меню
  • Указатель

Логотипом является верхняя полоска со стилизованной надписью "Python". Меню – это четыре пункта "Play", "Options", "Hall of Fame", "Quit". Но представление о них не знает, оно имеет доступ только к модели MainMenuModel, которая и инкапсулирует эти пункты. Модель содержит свойство текущего выбранного пункта (selected_item) и методы prev_item() и next_item(), которые позволяют выбирать предыдущий или следующий пункт. Метод get_item(num) возвращает графический объект, соответствующий пункту меню номер num. При этом модель следит, выбран этот пункт или нет, и возвращает соответственно светлый или тёмный вариант.

Представление занимается там, что получает у модели объекты-пункты меню и отрисовывает их по установленным координатам. Разделение обязанностей позволяет наполнять модель любым количеством пунктов меню, а представление автоматически подгонит позицию на экране, чтобы меню находилось в центре. Также при желании представление может располагать пункты не по вертикали, а по горизонтали и т.д. На то оно и представление.

Контроллер MainMenuController обслуживает нажатия на клавиши и вызывает у модели методы prev_item() и next_item(), чтобы указатель меню сдвигался вверх или вниз.

Но самое интересное происходит, если нажать клавишу Enter или пробел. Таким образом мы выбираем пункт меню и... что дальше?

Пока реализованы только пункты Play и Quit. При нажатии на Play вместо текущих контроллера, модели и представления должны создаться новые контроллер, модель и представление, которые соответствуют главному игровому режиму (то есть то, что было в прошлой части).

Чтобы сделать переходы от контроллера к контроллеру, была введена новая сущность Game. У неё есть статические свойства-константы режимов игры (MODE_MAIN_MENU, MODE_PLAY и т.д.), а также метод init_mode(mode), который, получив на вход параметр mode, как раз и создаёт триаду модель-контроллер-представление, соответствующую этому параметру.

Первично мы инициализуем игру с помощью game.init_mode(Game.MODE_MAIN_MENU). Игровой цикл в main.py теперь всегда направляет поток ввода в контроллер, который задан свойством game.controller. То есть какой контроллер был назначен этому свойству, такой и будет работать. Очевидно, сначала это будет MainMenuController. Затем, когда мы в этом контроллере обработаем клавишу Enter на пункте меню Play, он просто вызовет game.init_mode(Game.MODE_PLAY). Объект game установит себе новый контроллер (GameController), новую модель и новое представление. И главный игровой цикл продолжит работать, только теперь нажатия клавиш будут передаваться уже в новый контроллер, и видеть на экране мы будет уже не меню, а игру, потому что вместе с контроллером поменялись и представление, и модель.

Сама игра по-прежнему оформлена убого и кроме того, начав играть, мы пока не можем вернуться в главное меню. Это мы исправим в следующем выпуске. Мы сделаем подсчёт очков и жизней, и соответствующую логику для окончания игры и возврата в меню.

Были сделаны также косметические изменения. Классы разнесены в отдельные файлы (так легче давать ссылки и вообще редактировать). Кое-какие свойства переименованы и т.п. Да, и кстати INI-файл теперь не только для галочки: оттуда берутся размеры экрана.

Напоминаю, что проект становится больше, объяснять всё займёт немыслимое время, поэтому если что-то интересно или непонятно – спрашивайте в комментах.

Следующая часть: Подсчёт очков и первый баг

Читайте также:

Наука
7 млн интересуются