Snooder 21 — мой ремейк игры Snood™ 21: Процесс создания

Когда-то давно я учился в старших классах школы и у меня был очень популярный в то время мобильный телефон: Motorola C350. Именно на этом телефоне я впервые и познакомился с игрой Snood™ 21. Хотя Motorola C350 был в использовании у меня совсем недолго, я всё равно успел провести очень много времени в этом интересном и своеобразном карточном пасьянсе, играя в него в различных очередях и на очень скучных уроках. На мой взгляд, Snood™ 21 является просто отличной убивалкой времени и поможет скрасить томительное ожидание в самых различных ситуациях. Спустя годы, мой лучший друг напомнил мне об этой замечательной игре и я решил сделать её ремейк для Android OS, чтобы снова иметь возможность раскладывать карты по знакомым стратегиям и на современных смартфонах.



Snooder 21 на Motorola Droid 4 и Snood™ 21 на Motorola C350.

История Snood™ 21 берёт своё начало с оригинальной игры Snood, которую разработал David M. Dobson в 1996 году для персональных компьютеров Mac от Apple. Именно с этой игры и началась история незамысловатых и забавных персонажей, которые называются Снудами. Вселенная Снудов включает в себя огромное количество самых разных настольных, карточных и аркадных игр, которые теперь доступны на официальном сайте под различные платформы. К несчастью, я не смог найти там игру, аналогичную Snood™ 21. Видимо она выходила только на мобильные телефоны от Motorola.



Нативная игра Snood™ 21, запущенная на Motorola V150. Автор фотографии Никита Прокопчик (превью, увеличение по клику).

Разработчиком игры Snood™ 21 является компания THQ, которая в сотрудничестве с Motorola выпустила эту игру встроенной в прошивку различных бюджетных мобильных телефонов. THQ купила права использования имён персонажей и их изображений у идейного вдохновителя и даже создала Java-версию игры для монохромных телефонов с поддержкой Java. Помимо этого, существует и нативная версия для карманного компьютера Cybiko.

Правила игры довольно просты: необходимо помещать карты из колоды в столбцы, набирать в них 21 очко и стараться попасть в таблицу рекордов. Масти в игре заменены Снудами, кроме этого имеется несколько специальных карт, которые сразу очищают колонку. На подсчёт очков влияет столбец, в котором была собрана комбинация. Чем он правее, тем больше очков можно заработать. Игра заканчивается если истечёт время или заблокируются все столбцы. Более подробно правила Snood™ 21 описаны в инструкции, которая шла вместе с мобильным телефоном Motorola.



Страница из инструкции к мобильному телефону Motorola V150 с подробным описанием правил игры Snood™ 21.

В своём ремейке для Android OS я решил максимально сохранить геймплей и дизайн оригинальной игры. А поскольку права на название и изображения персонажей принадлежат компании Snood LLC., я решил переименовать игру в Snooder 21 и перерисовать спрайты главных героев. Новое название, конечно, не блещет оригинальностью, но зато остаётся в духе изначального.

Содержание:

1. Логика игры, отрисовка с помощью канваса класса SurfaceView
2. Обзор методов управления
3. Создание игровых ресурсов
4. Создание лаунчера с таблицей рекордов
5. Заключение, полезные ссылки и ресурсы

1. Логика игры, отрисовка с помощью канваса класса SurfaceView

Заниматься разработкой игры я решил в этот раз не в Eclipse, а в Android Studio, так как Google уже давно советует перейти именно на эту IDE.



Android Studio с открытым проектом игры Snooder 21 (превью, увеличение по клику).

Для отрисовки игрового контекста на экран я использую класс SnoodsSurfaceView, который является наследником системного класса SurfaceView и реализует интерфейсы SurfaceHolder.Callback и Runnable. Отрисовка, а также обсчёт игровой логики и очков происходит в отдельном потоке внутри перегруженного метода run():

Из метода run() вызывается метод tick(), в котором описана основная логика игры:

После вызова tick() происходит вызов метода render(), который формирует итоговую картинку и выводит её на канвас, отвечающий непосредственно за вывод изображения на экран:

Чтобы не делать наборы спрайтов для разных разрешений дисплеев Android-устройств, я решил рисовать всё на холсте размера 800×480, а потом этот холст растягивать на весь экран со сглаживанием или без. Это несколько неправильный подход, поскольку на слабых устройствах или на девайсах с большим разрешением экрана будет значительно проседать FPS. Эксперименты показали, что FPS проседает в основном из-за сглаживания, поэтому я решил сделать возможность его отключения. Поскольку этот подход позволял сэкономить огромное количество времени, я выбрал именно его.

Колода карт представляет из себя простой массив int[], длина которого изменяется в зависимости от сложности уровня игры. В начало массива добавляется необходимое количество обычных карт, а в конец массива добавляются шесть специальных карт, которые очищают столбец. После чего колода случайным образом тусуется. В методе flushDeck() и происходит вся эта кухня:

По значениям из массива int[] на игровое поле рендерятся две карты: текущая и следующая. После того, как карта помещена в столбец, текущая карта подменяется следующей, а следующая — уже следующей по значению массива. И так до самого конца игровой колоды:

Каждый отдельный столбец представлен как ArrayList<Bitmap>, а все колонки вместе представлены как ArrayList<Bitmap>[]. К примеру, так выглядит метод добавления карты в определённый столбец:

А методом drawCardDecs() на экран рендерятся все карты в колонках:

После набора 21 очка массив столбца просто очищается методом clear().

Простейшие анимации карт в игре представлены двумя способами. Первый напрямую зависит от количества кадров в секунду и может быть отрегулирован, а второй использует для анимации таймер с обратным отсчётом и зависит от времени. Анимации первого типа используются в основном для передвижения карт и их реализация неприлично проста: в методе tick() происходит изменение контролирующих расположение спрайта переменных-координат. Второй тип анимации используется для переключения спрайтов карт и реализован в классе SnoodsAnimationTimer, наследнике системного класса CountDownTimer со следующими методами:

Этот класс реализует простейшее попеременное переключение кадров. Основной игровой таймер тоже является наследником класса CountDownTimer и имплементирован в классе SnoodsGameTimer. После того, как время кончится, метод onFinish() просто вызывает конец игры. Ещё этот класс в методе onTick() контролирует переменную, которая отвечает за правильное отображение индикатора прогресса времени, который рисуется обычным прямоугольником.

Поскольку большая часть игровой логики и отрисовки заключена в классе SnoodsSurfaceView, он получился весьма громоздким. Если я найду свободное время, то обязательно сделаю рефакторинг и разобью его на отдельные классы. Примечательно, что вся игровая логика Snooder 21 была написана мной лишь за один вечер.

<< Перейти к содержанию

2. Обзор методов управления

В Snooder 21 я реализовал три варианта управления, первые два из них используют сенсорный экран, а третий — физическую клавиатуру. Поскольку я являюсь счастливым обладателем смартфонов с QWERTY-клавиатурой, третий метод я реализовал в первую очередь. Для обработки событий нажатий на кнопки достаточно перегрузить метод onKeyDown() в классе SnoodsSurfaceView. Не стоит забывать, что в конструкторе этого класса должен быть вызван метод requestFocus(), в противном случае события клавиатуры будут пролетать мимо.

Карты добавляются в столбец методом putCardToColumn(), который по сути лишь меняет управляющие переменные, а все изменения и добавление карты в колонку обеспечивает метод tick(), который вызывается в другом потоке.

Метод putCardToColumn() и его перегруженная версия используется и в реализации вариантов сенсорного управления. Первый вариант такого управления обеспечивает перетаскивание карт из колоды на необходимые столбцы, а второй перемещает верхнюю карту колоды в столбец, которого коснулся палец. Всё это поведение реализовано в перегруженном методе onTouchEvent() класса SnoodsGameActivity:

Поскольку я использую холст размера 800×480, мне приходится конвертировать все координаты касаний специальными методами:

Для наглядной визуализации доступности столбца я использую простую подсветку полупрозрачным прямоугольником зелёного и красного цветов.

Таким образом, при наведении карты на столбец он окрашивается в зелёный или красный цвет в зависимости от того, можно в него поместить карту или нет.



Подсветка активного столбца, скриншот с Motorola Photon Q (превью, увеличение по клику).

Управление автоматически отключается при проигрывании различных анимаций передвижений карт, чтобы избежать непредвиденных последствий.

<< Перейти к содержанию

3. Создание игровых ресурсов

Игровое поле Snooder 21 я попытался сделать максимально похожим на таковое из оригинальной игры и за несколько минут нарисовал его в свободном графическом редакторе GIMP, определив размеры холста в 800×480.



Игровое поле, скриншот с Motorola Photon Q (превью, увеличение по клику).

В качестве небольшой пасхалки я оставил векторное изображение Motorola C350 под колодой карт. Именно на этой модели мобильного телефона, которая являлась очень популярной в народе, и была оригинальная игра Snood™ 21. Это изображение можно увидеть пройдя уровень до конца и использовав последнюю карту.

Фоновая заставка, которая проигрывается при переходе на следующий уровень, тоже была нарисована мною в GIMP’е. На простом градиентном фоне, который символизирует небо, я использовал фильтр Gradient Flare для создания светила и группу из фильтров RGB Noise, Spread и Motion Blur для создания простой травы. Немного приправил тенями и, мне кажется, получилось достаточно симпатично:



Нарисованный в GIMP’е фон заставки.

В 2011 году Johannes Kopf, являющийся сотрудником компании Microsoft Research и профессор Dani Lischinski опубликовали научный доклад с описанием нового алгоритма депикселизации изображений, который значительно превосходит все существующие методы. Позже, в рамках инициативной программы по развитию проектов с открытым исходным кодом от компании GoogleGoogle Summer of Code 2013, этот алгоритм реализовали в отдельной библиотеке libdepixelize, написаной на языке программирования C++. Позже эту библиотеку включили в состав свободного редактора векторной графики Inkscape.



Демонстрация результата работы нового алгоритма Личински-Кофа.

Благодаря работе этих замечательных учёных и редактору Inkscape у меня появилась возможность нарисовать забавные спрайты-смайлики для игровых карт. Я отрисовывал в GIMP’е пикселизированное изображение небольшого размера, затем импортировал его в Inkscape, использовал там инструмент Trace Pixel Art и получал необходимый спрайт.



Пример создания спрайта для игровой карты в программе Inkscape с помощью инструмента Trace Pixel Art.

Для того, чтобы спрайты в формате PNG весили ещё меньше, я обработал их специальной утилитой optipng, которая доступна в репозиториях большинства дистрибутивов GNU/Linux.

Использование этой утилиты позволило уменьшить размер PNG-спрайтов приблизительно на 20%.

Подходящие звуки для игры я долго и упорно отбирал на тематических сайтах freesound и OpenGameArt.Org. Все они были опубликованы под свободными лицензиями, авторов звуковых эффектов я отметил в документе Sounds_Licenses.txt в своём репозитории.

<< Перейти к содержанию

4. Создание лаунчера с таблицей рекордов

Для того, чтобы было удобно работать с различными опциями, я вынес все настройки в специальный лаунчер, который сохраняет их при выходе из приложения и восстанавливает при повторном запуске. В лаунчере можно определить скорость анимации или задать имя, которое будет использовано для записей в таблице рекордов, которая находится здесь же.



Лаунчер Snooder 21 и таблица рекордов, скриншоты с Motorola Droid 4 (превью, увеличение по клику).

Для законченности я добавил в лаунчер обложку, которую тоже нарисовал в GIMP’е и диалоги About и Help с информацией и правилами игры.



Диалоги About и Help, скриншоты с Motorola Photon Q (превью, увеличение по клику).

Таблица рекордов образована двумя объектами класса TextView: первый отображает имена, а второй количество набранных очков. Обновление таблицы рекордов осуществляется методом updateHighScoreTable(), который берёт нужную информацию из вложенного класса SnoodsSettings и соединяет всё в строки с переносами, которые и отображают на экране объекты класса TextView:

Управлением таблицей рекордов занимается класс SnoodsScoreManager, методы которого выполняют различную работу, например, генерируют уникальное имя игрока при первом запуске игры, или проверяют то, что набранные очки действительно нужно вносить в таблицу. Если игрок выставит некорректное, например, пустое имя, то этот класс заменит его на Player или обрежет до 11 символов.

Метод insertScore() в своём теле запускает обновление таблицы рекордов в интерфейсном потоке. Набранные очки проверяются на рекорд при каждом проигрыше или при нажатии на клавишу Back во время игры.

<< Перейти к содержанию

5. Заключение, полезные ссылки и ресурсы

Создание ремейка игры Snood™ 21 на Android OS позволило мне разобраться в некоторых тонкостях сенсорного управления, овладеть базовыми навыками работы в мощнейших графических редакторах GIMP и Inkscape, а также использовать Android Studio вместе с системой автоматической сборки Gradle. Этот процесс дал мне огромное количество ценного опыта, я смог реализовать за короткое время весьма интересную карточную игру.

Размер установочного APK-пакета получился небольшим, всего 480 КБ. Основной вес приходится на спрайты и фоны достаточно большого разрешения. Поскольку я использовал только язык программирования Java, приложение должно отлично работать на всех доступных архитектурах процессоров, на которых работает Android OS.

Скачать APK-пакет Snooder 21, готовый для запуска на любом Android-устройстве, можно по этим ссылкам:

[Скачать APK-пакет Snooder 21, 480 КБ | Download Snooder 21 APK-package, 480 КB]

Все исходные коды и проект в целом выложен в репозиторий на ресурсе Github. Мои изменения и исходные файлы доступны под лицензией MIT, а лицензия CC BY 3.0 используется для всех созданных игровых ресурсов. Ссылка на репозиторий:

https://github.com/EXL/Snooder21

В этой работе я использовал огромное количество материалов, основные из них я выделю в полезных ссылках ниже. Огромное спасибо ресурсам stackoverflow.com и google.com за то, что они есть.

  1. Руководство по созданию клона игры Space Invaders с использованием отрисовки на SurfaceView;
  2. Исходники клона игры Babson Space Invaders на Github;
  3. Руководство по рисованию травы в GIMP;
  4. Inkscape tutorial: Tracing Pixel Art.

Update 06-MAR-2017: Прочитать информацию о новой версии моего ремейка Snooder 21 v1.1 с незначительными исправлениями и улучшениями можно по этой ссылке.

Update 05-MAY-2017: В проекте были обновлены компоненты Gradle, это ознаменовало выход новой версии Snooder 21 v1.2, скачать которую можно со странички проектов.

<< Перейти к содержанию

Android, Dev

Snooder 21 — мой ремейк игры Snood™ 21: Процесс создания: 2 комментария

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *