Найти в Дзене
ZDG

Пишем Питона на Питоне #19: Доделки

Оглавление

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

Код для этой части находится в ветке improvements на github. Вы можете смотреть там все файлы онлайн и также скачать зип-архив всей ветки.

В этом выпуске разберёмся с некоторыми назревшими доделками:

  1. Размер логотипа нужно адаптировать под разные разрешения экрана
  2. Хвост питона укорачивается очень медленно
  3. Управление должно быть более отзывчивым и исключать неправильное поведение питона

А теперь по порядку.

1. Размер логотипа

Логотип используется на нескольких игровых экранах, начиная с главного:

Сам логотип это картинка шириной 1280 пикселов:

-2

Поэтому, если ширина экрана 1280 пикселов, то картинка будет занимать ровно ширину экрана. Если же ширина экрана будет больше, то справа от картинки появится пустое место. Если меньше – картинка будет усечена справа.

Чтобы логотип всегда находился по центру и не имел зазоров по краям, применим смешанную технику. Логотип будет состоять из центральной части:

-3

и повторяющейся части:

-4

Центральная часть будет располагаться всегда по центру, а с помощью повторяющейся части мы "замостим плиткой" отступы слева и справа до края экрана:

тут с промежутками, чтобы было лучше видно
тут с промежутками, чтобы было лучше видно

В общем, нарезаем нужные части и переписываем код. Лого присутствует в представлениях главного меню, настроек игры, таблицы рекордов, конца игры и ввода имени. Надо изменить 5 представлений... И тут мы можем заслуженно порадоваться, так как предусмотрительно отнаследовали все эти представления от одного LogoView, и значит исправить нужно только одно.

В конструкторе добавляем код, чтобы один раз отцентрировать логотип, и сохраняем его горизонтальную координату (logo_x) в отдельной переменной. В методе render() берём текущие координаты левого и правого края логотипа (left_side и right_side). Пока координата левого края больше нуля, сдвигаем координату влево на ширину плитки и рисуем плитку. На правой координате тоже рисуем плитку и сдвигаем координату вправо. Проверять её не нужно. Так как логотип расположен по центру, то справа поместится столько же плиток, сколько слева.

Теперь логотип всегда будет по центру и без зазоров, а на маленьких экранах (800*600) он будет обрезаться более красиво адекватно:

-6

2. Хвост питона

Когда питон врезается в препятствие или идёт на выход, его хвост начинает укорачиваться. Пока хвост не укоротится полностью, ничего не происходит, игрок просто сидит и смотрит. Если хвост очень длинный, придётся смотреть довольно долго.

В контроллере GameController используется переменная speed, которая задаёт задержку перемещения питона. Она получена эмпирически и (пока) не регулируется. Идея состоит в том, что когда питон находится в состоянии, когда у него сокращается хвост, задержку надо уменьшать в два раза, например.

Это достигается добавлением одного условия, которое проверяет, в каком режиме находится питон, и прибавляет к счетчику либо полную задержку, либо половину.

3. Управление

С управлением связан один обидный нюанс. Питон ползёт со скоростью примерно 8 кадров в секунду. Значит, изменить направление движения он тоже может не чаще, чем 8 раз в секунду.

Контроллер GameController может назначать питону направление с любой частотой, но питон отработает это направление только раз в 1/8 секунды.

Следовательно, появляются "пропущенные направления". Происходит это так:

  1. Игрок оценивает ситуацию и решает быстро развернуться назад. Для этого он последовательно нажимает две стрелки. Например, питон ползёт вверх, а игрок нажимает вправо и вниз, чтобы развернуть его.
  2. Контроллер, получив стрелку вправо, назначает питону движение вправо. Затем, получив стрелку вниз, назначает движение вниз.
  3. Но питон не успел сдвинуться между двумя нажатиями стрелок. И когда ему наступает время двигаться, его направление уже установлено вниз. А направление вправо не было отработано. Так как питон двигался вверх, он начинает отрабатывать текущее направление и движется вниз, то есть наезжает сам на себя. И умирает.

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

Я, однако, решил попробовать по-другому и посмотреть, что получится. Решение простое: как только питону задаётся новое направление (которое отличается от текущего), счётчик задержки сбрасывается на ноль. И тогда питон сразу отработает это направление. Но в то же время это приведёт к тому, что питон в эти моменты будет двигаться быстрее – фактически с максимальной скоростью, с какой игрок может нажимать на стрелки. Я попробовал это сделать, и результат мне на самом деле понравился. Быстро меняя направление движения, можно заставить питона двигаться "ступеньками по диагонали" быстрее (похоже на распрыжку в Quake). Но и играть так сложнее. Если игроку так нравится, то пусть играет.

На этом пока всё. В следующем выпуске поработаем над балансом вознаграждений игрока и попробуем скомпилировать из проекта .exe-файл.

Читайте дальше: