Иногда программисты изобретают свои «велосипеды», но действительно ли это плохо, особенно если творение не отличимо от оригинала, а автор получает бесценный опыт?
Эта история началась чуть более года назад с появлением у моей супруги современного смартфона. Она попросила найти пасьянс «Косынку», такой же как был когда-то на настольной Windows. Просмотрев десяток программ, я был неприятно удивлен — почте везде было неудобное управление, спорные картинки карт, море дополнительных наворотов вроде 250 пасьянсов в одном, установки фотографии на рубашку и блекджека с блудницами. В результате, выбрали один из более-менее годных вариантов и на какое-то время об этом забыли.
Пролетел год и я начал писать программы для мобильных. При этом ребром стал вопрос кросс-платформенности, отладки in-app покупок, подготовки контента под разные платформы. Была мысль сделать для пробы пера «Тетрис» или очередной калькулятор, но все же в качестве «велосипеда» я выбрал «Косынку». Идейным стрежнем проекта стало максимально точное повторение старого, доброго пасьянса из набора игр Windows.
Контент
Первая проблема возникла с графикой: в интернете полно рисунков карт, многие из них бесплатны, но почти все довольно вычурны, странно смотрятся на мобильных экранах, да и просто не похожи на старые карты из cards.dll. Карты для Windows попиксельно рисовала талантливый дизайнер Сюзан Кэр в 1989м году, в 16-ти цветном режим. При желании их легко найти в сети, но использовать наврядли можно без нарушений IP. Гораздо интереснее оказались карты, используемые в некоторых играх мира Linux — они распостранялись под GPL лицензией, хоть и выглядели немного странно, с черно-белыми старшими картами (фигурами). Автором этих карт оказался тов. Oxymoron, на сайте которого лежат сами картинки и скрипт их сборки. Он нарисовал собственные цифры и иконки мастей, а фигуры взял из неизвестного источника, но довольно похожие на оригинал. Я немного доработал скрипт, чтобы он сохранял карты в PNG, добавил прозрачность, а заодно раскрасил вручную старшие карты. Для иконки туза пик была нарисована собственная стилизованная картинка, по аналогии с оригиналом напоминающая кельтский узор. Она же и стала иконкой программы.
Для рубашки была выбрана самая приятная (на мой взгляд) картинка с пляжем и пальмой с ручной прорисовкой. Получилось очень узнаваемо — взгляд на картинке не задерживается, хотя если всмотреться, то разница очевидна.
Геймплей
Как оказалось, геймплей в «Косынке» не так уж и прост за счет подсчета очков, таймера, выдачи по одной/три карты, а заодно и режима Vegas. К примеру, игра на деньги с выдачей по одной карте (т.е. без возможности переворачивать колоду), заметно отличается от стандартной: ее цель перенести как можно больше карт к тузам и набрать более $42, чтобы выйти из минуса и начать следующую партию, если пасьянс не сложился. В игре же на счет перенос карты из колоды «вниз», а потом к тузам дает 15 очков, в то время как сразу к тузам — только 10. Естественно, задокументировано это очень условно, потому пришлось загнать оригинальную игру в wine и провести полноценный ресерч.
Код
Бизнес логику программы я написал на чистой Java 1.6, без использования сторонних библиотек, Android, Swing и пр. Для Android эта часть собирается в виде отдельной библиотеки и подключается к GUI проекту без особых проблем, а вот для других ОС я решил идти нестандартным путем и не заниматься портированием «в лоб» на другие языки. После некоторой обработки напильником проект Sharpen смог преобразовать этот код в чистый C#, что открыло путь к реализации под iOS c помощью MonoTouch, а в будующем и для Windows Phone 7/8. Простейшие юнит-тесты показали, что логика работы не изменилась, трансляция прошла успешно. В среде MonoTouch я без особых нюансов реализовал отображение GUI, отладил игру на эмуляторе и iPod Touch и отправил на одобрение в iTunes Store. Настройки программы я реализовал с помощью внешнего биндинга к KGN.InAppSettings, споткнувшись о некоторые мелочи вроде отсутствия поддержки thumb для внешних библиотек.
Проблемы
После недели аппрува в Apple, моя «Классическая Косынка» появилась в iTunes Store. Я ожидал критики графики или возможных лицензионных споров, но в первый же день все отзывы были однозначны: игра вылетает сразу при запуске. Игру из магазина я убрал и начал изучать проблемы. У моих знакомых игра запускалась отлично, эмулятор и iPod Touch 4g тоже не показывали никаких сбоев. Понадобилось несколько дней и помощь форумчан, чтобы найти первый серьезный баг: в региональных стандартах iOS для Европы и Украины указан десятичный разделитель «точка», а в России это уже «запятая». Соответственно, преобразование float в строку работало на одних устройствах и крашилось на других. В течение недели после отправки на аппрув, оказалось, что игра еще и крашилась при запуске в альбомном режиме. На iPod и iPhone все программы стартуют в портретной ориентации, потому обнаруживается это только на iPad, которого у меня не было. На ре-аппрув ушла еще неделя, за которорую игра окончательно пропала из категории «Новое» и успешно утонула за пределами Top 1000. К тому же, иконка с прозрачным фоном, отлично принятая в Android Market, была похабно обработана скриптами Apple и стала откровенно не симпатичной.
High-definition
К тому моменту, как проект заработал нормально, были заменены иконки и пр., у меня появился новый iPad, где я обнаружил, что разрешения карт откровенно не хватает для 9.7" экрана, да и на Retina Display «прыгающие карты» откровенно тормозят. Борьба с лагами заняла пару дней, за которые я успел основательно породниться с Core Animation, а вот для улучшения разрешения пришлось нанять дизайнера. Результатом его работы стали цифры, буквы и масти высокого разрешения, максимально похожие по стилю на оригинал. Фигуры я увеличил с помощью Photo Zoom Pro, чтобы не потерять аутентичность пиксельной графики. Вышло не идеально, но все же довольно удачно.
На эту работу было потрачено немало усилий, потому было логично выпустить отдельно HD версию, а заодно добавить внутреигровую покупку в обычную версию. С реализацией In-App Purchases под MonoTouch оказалось не все просто, а чтобы смотрелось это органично, я решил избавиться от KGN.InAppSettings и сделать единый интерфейс для настроек и покупок. Технические детали я тут описывать не буду, но набралось их немало, включая мартышкин труд по созданию собственных Settings, идентичных системным, борьба с отсутствием документации к StoreKit для Mono, разные баги с отладкой покупок и пр.
Профит
Игра не стала шедевром, не попала в топы, да и наврядли окупит стоимость разработки и работу дизайнера, но все же теперь у меня на всех устройствах (включая и смартфон, с которого все началось) есть «Косынка», максимально похожая на оригинал, ставший родным еще со времен Windows 3.1. Опыт написания портируемого кода на Java и переноса его на C# оказался просто бесценным — подобным методом моей командой портировано уже несколько крупных Android проектов на iOS, а за счет отладки на небольшой игре получилось неплохо изучить подводные грабли MonoTouch и вообще разработки под iOS, а заодно написать некое количество полезных библиотек. Может кто-то и посмеется над этой историей, но как по мне, «велосипед» вышел весьма годным, а время было потрачено совсем не зря.
Post Scriptum
Я специально избегал углубления в подробности портирования и работы с MonoTouch, потому что каждая из них достойна отдельного топика. Рано или поздно соберусь с силами и выложу на суд общественности свой класс для In-Game Settings, менеджер покупок и пр.
Ссылки на проект я не выкладываю, чтобы не посчитали рекламой.
Если кому нужен обновленный скрипт генерации карт, пишите на scanwords@runserver.net, он является derivative work от GPL проекта, потому выложу без проблем.
Автор: Nomad1