Предыдущие части: Таблица рекордов, Шрифт, Остановите музыку, Включите звук, Жизни и модальные окна, Подсчёт очков, Главное меню, Геймплей, Есть ли у него душа, Организация ввода, View, Визуализация поля, Загрузка уровня, INI-файл, Пишем Питона на Питоне!
Код для этой части находится в ветке looks на github. Вы можете смотреть там все файлы онлайн и также скачать зип-архив всей ветки.
В этом выпуске сделаем так, чтобы у головы питона были глаза, и чтобы яблоко рисовалось с пульсирующей анимацией. Глаза питона должны всегда смотреть на яблоко. Теоретически должно получиться так:
Глаза будут рисоваться поверх головы как два жёлтых квадрата. А зрачки в них – чёрные квадраты – должны перемещаться по периметру глаз, чтобы всегда смотреть в сторону яблока.
Расположение глаз на голове также зависит от того, в какую сторону движется питон:
Для решения этой задачи нужно:
- Иметь данные о текущем направлении движения головы.
- Иметь данные о местоположении яблока.
Этими сведениями располагает контроллер GameController, который собственно занимается перемещением головы и генерацией яблок. Но эти свойства хранятся в не очень удобном для нашей задачи виде, и кроме того, они нужны в представлении, а представление о них не знает. Поэтому сделаем так, чтобы контроллер переводил эти свойства в удобный вид и записывал их в представление GameView.
Это будут уже свойства представления:
- head_dx, head_dy: направление движения движения головы по осям
- apple_x, apple_y: координаты яблока (уже реальные пиксельные координаты на экране)
Начнём дорабатывать представление GameView, чтобы нарисовать глаза. Они будут рисоваться сразу же, как только нарисована голова. Просто напишем отдельный метод draw_eyes(), чтобы не загромождать код.
Метод рисования глаз оказался длиннее, чем метод рисования всего уровня. Приходится проводить нудные вычисления:
- Голова занимает одну клетку поля, а размер клетки зависит от разрешения экрана и размеров уровня. Поэтому размеры глаза и зрачка зависят от размера головы, их надо вычислить. (Это я всё-таки перенёс в конструктор, чтобы не вычислять в каждом кадре)
- Затем надо понять, как ориентированы глаза по отношению к голове. Проверяем направления головы head_dx, head_dy и переносим координаты глаз в нужную сторону.
- Затем двигаем зрачок внутри глаза. Если яблоко левее его, он сдвигается влево, если выше, то вверх и т.д.
Только после этого этого можно нарисовать глаза и зрачки.
Результат налицо – питон сразу стал гораздо привлекательнее и живее выглядеть:
Зрачки внутри глаз можно позиционировать и более точно, но для этого придётся привлекать математику с пересечением линий. Пока не буду усложнять, так как не уверен, будет ли заметен эффект.
Пульсация яблока
Сделаем яблоко пульсирующим, чтобы немного оживить пейзаж. Его размер будет меняться от половинного до нормального. А для придания этому изменению именно эффекта пульсации будем использовать технику твининга, описанную ранее в статье Твининг для светлячков. В данном случае функцией твининга будет служить косинус от -пи до пи, а прогресс от 0 до 1 описывается отношением сосчитанных тиков к числу максимальных тиков.
Так как тики уже используются в представлении EnterNameView для анимации курсора, я переместил само свойство ticks в базовый класс View и туда же добавил статическое свойство MAX_TICKS и метод update_ticks(), который считает тики и обнуляет их после достижения MAX_TICKS. Теперь все представления, использующие тики, будут обращаться к свойствам и методу базового представления.
Так как в рисовании яблока тоже появились нудные вычисления, я сделал в представлении GameView отдельный метод draw_apple().
На картинке этого не показать, поэтому вот видео:
В следующем выпуске сделаем несколько уровней, переход от уровня к уровню, и игру можно будет считать практически готовой.
Читайте дальше: Уровни и конец игры
Читайте также:
- ООП в Python: особенности реализации