Я разработчик игры Raildale, и в этой статье расскажу вам историю разработки. Но для начала скажу несколько слов о самой игре. На поле появляются разноцветные города, которые нужно соединять железной дорогой. Из городов выходят поезда, и их нужно отправлять в город соответствующего цвета, используя стрелки и светофоры и избегая столкновений. Еще есть разные дополнительные фичи: ремонтные поезда, экспрессы и другие. На мой взгляд игра получилась очень интересная, да и отзывы я пока что получал только положительные. Игра непростая и пройти ее действительно сложно. Raildale доступна под iOS и Mac OS X в App Store.
Подробнее об игре можно посмотреть на www.raildale.com.
Поэтому я задумался о реализации своего проекта. Я думал о разработке приложения или игры под iOS. В конце концов я решил делать игру. Это максимально далеко от того, чем я занимался до этого, и поэтому очень интересно. Разумеется, проект не должен был быть очень большим, так как у меня не было опыта ни в разработке игр, ни в маркетинге.
У меня было много идей, но остановил я свой выбор на паровозиках. Эта была та игра, в которую я сам бы с удовольствием поиграл. Прямо скажу, идея не нова, в детстве я играл в похожую игру. Ожидал найти что–то подобное под iPad, но все, что было мне совсем не понравилось. Поэтому я решил, что это отличный вариант для первого проекта.
В общем я решил уволиться и заняться своим проектом. Зарплата у меня была хорошая, так что были некоторые сбережения. Поэтому финансы не довлели и можно было спокойно поработать некоторое время без прибыли, тем более жена продолжала работать. Но когда зашел разговор об увольнении, руководство предложило несколько интересных для меня задач, и я решил остаться еще на какое–то время. В результате уволился я только в июне 2013 года. Все это время я немножко вел разработку игры параллельно с работой в свободное время, но много времени на это я уделить никак не мог. Потом в июле я еще на 3 недели съездил в Исландию в отпуск. Так что по полной в работу я окунулся только в августе 2013.
Для разработки я использовал JetBrains AppCode. XCode тоже неплохое IDE, но мне сложно сравнивать, я до этого пользовался IDEA и привык ко многому. Точно могу сказать, что в AppCode отладчик гораздо удобнее. Правда, в XCode есть прекрасная утилита для отладки рисования в OpenGL. Она может вывести все операции одного кадра, что иногда очень удобно, даже пытается что–то подсказывать. Так что, можно сказать, XCode я тоже использовал.
Через некоторое время я понял, что Objective–C меня раздражает. Причин много, я писал об этом статью (англ.). Конечно, далеко не все согласны со мной, но к моим методикам разработки Objective–C точно не очень хорошо подходит, хотя в Objective–C есть и интересные идеи. Поэтому я разрабатывал свой язык параллельно с разработкой игры и назвал его Objective–D. Я писал об этом отдельную статью на Хабре.
Для рисования спрайтов я использовал Sketch – векторный редактор под Mac. Хорошая в целом программа, немного глючная, правда. К тому же почему–то нет возможности выгрузить результат в произвольное разрешение. Только в том, в котором нарисовано или в 2 раза больше для ретины. Что очень странно и неудобно, особенно для иконки: приходится копировать и уменьшать вручную. И еще недостаток – необоснованно большой размер файлов, что неудобно при работе с VCS.
Я столкнулся с проблемой поворотов поездов. Для этого приходится рисовать вагончики под каждый угол, что занимало очень много времени. Да и результат был не очень хорошим – поезд дергался. Чтобы этого эффекта не было, нужно было нарисовать много углов. Тогда мне пришла в голову идея использовать 3D редактор для этого. Я выбрал Cheetah3D, купил модельку вагончика за пару долларов, выставил углы камеры, как в изометрической проекции, настроил свет. Я вращал вагончик вокруг своей оси и делал снимки. Получилось гораздо быстрее, чем рисование, но удовлетворительный результата достигался только при очень большом количестве углов поворота. Поэтому файл с этими углами получался громадным, особенно для ретины. С таким файлом мой iPad справлялся плохо – все откровенно тормозило.
Я решил попробовать отказаться от 2D и перейти в 3D. Тем более что я уже немного познакомился с 3D редактором. Я стал искать движок для 3D и наверное самым очевидным выбором было бы Unity3D. По нему много документации и его в основном хвалят. Но мне не понравилось, что там множество операций делаются в конструкторе, а мне хотелось писать код.
Я попробовал Cocos3D – расширение Cocos2D до 3D, но мне эта библиотека совершенно не понравилась. Те же самые проблемы, что и в Cocos2D, плюс почти полное отсутствие документации. В результате я не нашел ни одного движка, который бы мне подошел, и решил попробовать просто OpenGL.
Немного помучился, чтобы добиться вывода треугольника и экранного цикла. Начал разрабатывать игру, параллельно выделяя общую библиотеку для будущих игр. Основная идея – разделение кода на слои и изоляция изменяемых данных. Таким образом, почти все изменяемые данные изолированы в слое контроллеров, а слой отображения содержит только чистые функции рисования. В слое отображения допускаются изменяемые данные, необходимые только для кэширования или анимации. Слой контроллеров я покрыл автоматическими тестами. В результате качеством кода игры я остался удовлетворен, мне приятно что–то там дорабатывать и хочется еще игру улучшать. Когда код плохой, такого желания обычно не возникает.
В начале я нашел не очень удачные руководства по OpenGL. Там использовались такие вещи, как стэк матриц, например. Когда я добрался до написания шейдеров, оказалось, что матрицы в шейдер не передаются, да и вообще все это уже давно устарело, как и много другое. Пришлось почти все, что я сделал до этого переделать на современный манер. Так что важно сразу найти правильное руководство. Я бы посоветовал вот это.
Изначально я разрабатывал просто под Mac, так проще тестировать: не нужно подключать устройство к компьютеру. На эмуляторе игры проверять вообще бесполезно – жутко тормозит. Когда что–то стало вырисовываться, решил попробовать перенести на iOS. Основная проблема была в том, что язык шейдеров в OpenGL ES немного отличается от обычного. Но я справился довольно быстро.
В игре достаточно простая модель освещения – один глобальный направленный источник света (солнце). Теней у меня изначально не было и я решил, что было бы здорово их добавить. Для этого я использовал карты теней. Это не было очень сложно для моего освещения, но карта теней съедает много ресурсов, так как приходится рисовать многие вещи по два раза. Игра стала тормозить, и я занялся оптимизацией.
В этом деле довольно неплохо помогают инструменты Apple: есть специальный инструмент, который показывает вам возможные проблемы и советует, как их решить. Очень полезный инструмент для начинающего разработчика OpenGL. Например, для меня было открытием, что не стоит вызывать функции OpenGL, которые меняют состояния с одними и теми же параметрами. Они напрямую передаются в графический процессор, без проверки того, совпадает ли это состояние с текущим. Так что эту проверку нужно делать самому. Как ни странно, это небольшое изменение сильно улучшило производительность. Кроме того, сильно улучшило ситуацию использование Vertex Array Object (VAO).
Для оживления картинки добавил в игру ветер, дождь и снег. Ветер клонит деревья, сносит дым поездов и осадки. Основное направление и сила ветра не меняется в течение уровня, но периодически случаются порывы ветра. Громкость звука ветра меняется в зависимости от силы. Кроме того, также для оживления, добавил звуки птиц. Они отличаются для разных локаций и погоды, воспроизводятся в случайный момент с указанной для конкретного звука средней периодичностью.
Я прикрутил физический движок Bullet для того, чтобы моделировать разлетание вагончиков при столкновении. Первые результаты оказались довольно скучными – вагончики только немного сходили с рельсов. Тогда я решил применить эффект, который часто применяют в фильмах для повышения зрелищности: подкинул вагончики в воздух в момент столкновения и придал им случайное вращение. По–моему, получилось отлично.
Ближе к готовности я выложил версию на TestFlight для организации бета–тестирования. Отличный сервис и удивительно, что бесплатный. Я встроил их SDK, которое позволяет выставлять контрольные точки, чтобы понимать, куда заходили тестеры. Также оно собирает крэш–репорты в том числе и уже на рабочей версии. Это очень полезно, так как эти репорты должны вроде бы появляться в iTunesConnect, но это очень странно работает и далеко не всегда они там оказываются. Не могу сказать, правда, что бета–тестинг очень удался. Я опубликовал предложение о тестировании на форумах. Люди откликнулись, но их целью в основном было не тестирование, а просто поиграть. Поэтому баг–репортов я не получил, но хотя бы поиграли на разных устройствах, и игра не падала.
Когда игра была уже близка к готовности, я заказал перевод на One Hour Translation. Сервис мне понравился: быстро, удобно и дешевле я не нашел. Правда, про качество перевода мне сложно сказать. Можно заказывать и очень маленькие тексты. Я дозаказал потом фразу из 5–ти слов. Цена определяется только количеством слов. Я заказывал перевод с английского на бразильский португальский, французский, немецкий, итальянский, испанский, японский, корейский и китайский упрощенный. На английский я перевел сам и заказал пруфридинг, то есть мой текст проверил англоговорящий человек. Получается примерно в 7 раз дешевле перевода, да и качественнее, я думаю. Так что хороший путь, если неплохо владеете английским.
С локализацией возникла небольшая проблема. Для вывода текста я использовал битмэп шрифты. То есть имеется картинка с буквами и файл, в котором написано, где какая буква на этой картинке расположена. Но такой метод совсем не подходит для азиатских языков. Так что пришлось быстро менять систему вывода текста и рисовать сначала текстуру с буквами методами iOS.
Вообще локализация оказалась процессом небыстрым. iTunesConnect очень неудобен и работает неторопливо. Вроде бы простая задача перевести название досок в GameCenter превращается в пытку. Но мне удалось найти решение – iTunesConnect Transporter. Он позволяет написать все, что есть в iTunesConnect, в xml–файле и загрузить его вместе со скриншотами. Это меня спасло.
Во время разработки я записывал, сколько времени и на что я потратил. На момент написания статьи:
Это моя первая игра, так что времени на все можно было бы затратить меньше. Про маркетинг, например, я был вынужден прочитать множество информации, попробовать то, что не имеет смысла. Все равно, не могу понять, как получилось так много времени. Когда занимаешься маркетингом время утекает, а кажется, что ничего и не сделал.
Апрув занял 2 дня для Мак–версии и 5 дней для iOS. На данный момент цена $1.99. 15 промо–кодов для iOS версии можно получить здесь. Было бы очень интересно узнать ваше мнение. Я собираюсь улучшать игру и поэтому хотелось бы услышать, что бы вы улучшили в игре, что понравилось, что нет.
Знаю, что на Хабре любят читать также о маркетинге приложения. Разумеется это интересно, чтобы получить представление о прибылях, поучиться на чужих ошибках и успехах. Но сейчас об этом немного рано говорить, так как игра вышла совсем недавно. Думаю, выводы можно будет сделать примерно через месяц.
Скачать Raildale можно здесь.
Подробнее об игре можно посмотреть на www.raildale.com.
Предыстория
2 года назад (осень 2012) я работал программистом и занимался на тот момент системами управления предприятием уже 10 лет. У таких систем есть одно общее свойство: эти проекты никогда не кончаются. Работа мне нравилась, проект и задачи были интересные, но за 10 лет я устал от этой области. К тому же хотелось больше свободы в принятии технологических и интерфейсных решений.Поэтому я задумался о реализации своего проекта. Я думал о разработке приложения или игры под iOS. В конце концов я решил делать игру. Это максимально далеко от того, чем я занимался до этого, и поэтому очень интересно. Разумеется, проект не должен был быть очень большим, так как у меня не было опыта ни в разработке игр, ни в маркетинге.
У меня было много идей, но остановил я свой выбор на паровозиках. Эта была та игра, в которую я сам бы с удовольствием поиграл. Прямо скажу, идея не нова, в детстве я играл в похожую игру. Ожидал найти что–то подобное под iPad, но все, что было мне совсем не понравилось. Поэтому я решил, что это отличный вариант для первого проекта.
В общем я решил уволиться и заняться своим проектом. Зарплата у меня была хорошая, так что были некоторые сбережения. Поэтому финансы не довлели и можно было спокойно поработать некоторое время без прибыли, тем более жена продолжала работать. Но когда зашел разговор об увольнении, руководство предложило несколько интересных для меня задач, и я решил остаться еще на какое–то время. В результате уволился я только в июне 2013 года. Все это время я немножко вел разработку игры параллельно с работой в свободное время, но много времени на это я уделить никак не мог. Потом в июле я еще на 3 недели съездил в Исландию в отпуск. Так что по полной в работу я окунулся только в августе 2013.
2D
Изначально я разрабатывал игру в 2D в изометрической проекции. Я использовал Cocos2D – самый распространенный движок для 2D игр под iOS сегодня. Не могу сказать, что он мне понравился. Основная проблема, что он использует модель спрайтов. А это практически исключает разделение игры на слои (модель, контроллер, представление) и делает невозможным изоляцию состояния. У меня не получалось с ним добиться кода, который бы мне понравился. Все время получался самозапутывающийся код. Я пытался найти аналоги, но все, что я нашел было построено по тому же принципу. А Cocos2D все таки обладает неплохой документацией и активным сообществом, что безусловно плюс.Для разработки я использовал JetBrains AppCode. XCode тоже неплохое IDE, но мне сложно сравнивать, я до этого пользовался IDEA и привык ко многому. Точно могу сказать, что в AppCode отладчик гораздо удобнее. Правда, в XCode есть прекрасная утилита для отладки рисования в OpenGL. Она может вывести все операции одного кадра, что иногда очень удобно, даже пытается что–то подсказывать. Так что, можно сказать, XCode я тоже использовал.
Через некоторое время я понял, что Objective–C меня раздражает. Причин много, я писал об этом статью (англ.). Конечно, далеко не все согласны со мной, но к моим методикам разработки Objective–C точно не очень хорошо подходит, хотя в Objective–C есть и интересные идеи. Поэтому я разрабатывал свой язык параллельно с разработкой игры и назвал его Objective–D. Я писал об этом отдельную статью на Хабре.
Для рисования спрайтов я использовал Sketch – векторный редактор под Mac. Хорошая в целом программа, немного глючная, правда. К тому же почему–то нет возможности выгрузить результат в произвольное разрешение. Только в том, в котором нарисовано или в 2 раза больше для ретины. Что очень странно и неудобно, особенно для иконки: приходится копировать и уменьшать вручную. И еще недостаток – необоснованно большой размер файлов, что неудобно при работе с VCS.
Я столкнулся с проблемой поворотов поездов. Для этого приходится рисовать вагончики под каждый угол, что занимало очень много времени. Да и результат был не очень хорошим – поезд дергался. Чтобы этого эффекта не было, нужно было нарисовать много углов. Тогда мне пришла в голову идея использовать 3D редактор для этого. Я выбрал Cheetah3D, купил модельку вагончика за пару долларов, выставил углы камеры, как в изометрической проекции, настроил свет. Я вращал вагончик вокруг своей оси и делал снимки. Получилось гораздо быстрее, чем рисование, но удовлетворительный результата достигался только при очень большом количестве углов поворота. Поэтому файл с этими углами получался громадным, особенно для ретины. С таким файлом мой iPad справлялся плохо – все откровенно тормозило.
3D
Я решил попробовать отказаться от 2D и перейти в 3D. Тем более что я уже немного познакомился с 3D редактором. Я стал искать движок для 3D и наверное самым очевидным выбором было бы Unity3D. По нему много документации и его в основном хвалят. Но мне не понравилось, что там множество операций делаются в конструкторе, а мне хотелось писать код.
Я попробовал Cocos3D – расширение Cocos2D до 3D, но мне эта библиотека совершенно не понравилась. Те же самые проблемы, что и в Cocos2D, плюс почти полное отсутствие документации. В результате я не нашел ни одного движка, который бы мне подошел, и решил попробовать просто OpenGL.
Немного помучился, чтобы добиться вывода треугольника и экранного цикла. Начал разрабатывать игру, параллельно выделяя общую библиотеку для будущих игр. Основная идея – разделение кода на слои и изоляция изменяемых данных. Таким образом, почти все изменяемые данные изолированы в слое контроллеров, а слой отображения содержит только чистые функции рисования. В слое отображения допускаются изменяемые данные, необходимые только для кэширования или анимации. Слой контроллеров я покрыл автоматическими тестами. В результате качеством кода игры я остался удовлетворен, мне приятно что–то там дорабатывать и хочется еще игру улучшать. Когда код плохой, такого желания обычно не возникает.
В начале я нашел не очень удачные руководства по OpenGL. Там использовались такие вещи, как стэк матриц, например. Когда я добрался до написания шейдеров, оказалось, что матрицы в шейдер не передаются, да и вообще все это уже давно устарело, как и много другое. Пришлось почти все, что я сделал до этого переделать на современный манер. Так что важно сразу найти правильное руководство. Я бы посоветовал вот это.
Изначально я разрабатывал просто под Mac, так проще тестировать: не нужно подключать устройство к компьютеру. На эмуляторе игры проверять вообще бесполезно – жутко тормозит. Когда что–то стало вырисовываться, решил попробовать перенести на iOS. Основная проблема была в том, что язык шейдеров в OpenGL ES немного отличается от обычного. Но я справился довольно быстро.
В игре достаточно простая модель освещения – один глобальный направленный источник света (солнце). Теней у меня изначально не было и я решил, что было бы здорово их добавить. Для этого я использовал карты теней. Это не было очень сложно для моего освещения, но карта теней съедает много ресурсов, так как приходится рисовать многие вещи по два раза. Игра стала тормозить, и я занялся оптимизацией.
В этом деле довольно неплохо помогают инструменты Apple: есть специальный инструмент, который показывает вам возможные проблемы и советует, как их решить. Очень полезный инструмент для начинающего разработчика OpenGL. Например, для меня было открытием, что не стоит вызывать функции OpenGL, которые меняют состояния с одними и теми же параметрами. Они напрямую передаются в графический процессор, без проверки того, совпадает ли это состояние с текущим. Так что эту проверку нужно делать самому. Как ни странно, это небольшое изменение сильно улучшило производительность. Кроме того, сильно улучшило ситуацию использование Vertex Array Object (VAO).
Для оживления картинки добавил в игру ветер, дождь и снег. Ветер клонит деревья, сносит дым поездов и осадки. Основное направление и сила ветра не меняется в течение уровня, но периодически случаются порывы ветра. Громкость звука ветра меняется в зависимости от силы. Кроме того, также для оживления, добавил звуки птиц. Они отличаются для разных локаций и погоды, воспроизводятся в случайный момент с указанной для конкретного звука средней периодичностью.
Я прикрутил физический движок Bullet для того, чтобы моделировать разлетание вагончиков при столкновении. Первые результаты оказались довольно скучными – вагончики только немного сходили с рельсов. Тогда я решил применить эффект, который часто применяют в фильмах для повышения зрелищности: подкинул вагончики в воздух в момент столкновения и придал им случайное вращение. По–моему, получилось отлично.
Завершение
Тестированием игры занималась моя жена. Для нее тестирование не было в новинку – она занимается разработкой программного обеспечения и тестировать ей до этого приходилось немало. Ей удалось выявить множество проблем и недочетов. Она прошла игру на трех разных устройствах, чего пока не удалось мне. Я застрял на 15-ом из 16-ти уровней, но рано или поздно я все-таки рассчитываю ее пройти. Как ни странно, мне самому интересно играть в Raildale. Често говоря, думал, что к концу разработки желания поиграть у меня не останется.Ближе к готовности я выложил версию на TestFlight для организации бета–тестирования. Отличный сервис и удивительно, что бесплатный. Я встроил их SDK, которое позволяет выставлять контрольные точки, чтобы понимать, куда заходили тестеры. Также оно собирает крэш–репорты в том числе и уже на рабочей версии. Это очень полезно, так как эти репорты должны вроде бы появляться в iTunesConnect, но это очень странно работает и далеко не всегда они там оказываются. Не могу сказать, правда, что бета–тестинг очень удался. Я опубликовал предложение о тестировании на форумах. Люди откликнулись, но их целью в основном было не тестирование, а просто поиграть. Поэтому баг–репортов я не получил, но хотя бы поиграли на разных устройствах, и игра не падала.
Когда игра была уже близка к готовности, я заказал перевод на One Hour Translation. Сервис мне понравился: быстро, удобно и дешевле я не нашел. Правда, про качество перевода мне сложно сказать. Можно заказывать и очень маленькие тексты. Я дозаказал потом фразу из 5–ти слов. Цена определяется только количеством слов. Я заказывал перевод с английского на бразильский португальский, французский, немецкий, итальянский, испанский, японский, корейский и китайский упрощенный. На английский я перевел сам и заказал пруфридинг, то есть мой текст проверил англоговорящий человек. Получается примерно в 7 раз дешевле перевода, да и качественнее, я думаю. Так что хороший путь, если неплохо владеете английским.
С локализацией возникла небольшая проблема. Для вывода текста я использовал битмэп шрифты. То есть имеется картинка с буквами и файл, в котором написано, где какая буква на этой картинке расположена. Но такой метод совсем не подходит для азиатских языков. Так что пришлось быстро менять систему вывода текста и рисовать сначала текстуру с буквами методами iOS.
Вообще локализация оказалась процессом небыстрым. iTunesConnect очень неудобен и работает неторопливо. Вроде бы простая задача перевести название досок в GameCenter превращается в пытку. Но мне удалось найти решение – iTunesConnect Transporter. Он позволяет написать все, что есть в iTunesConnect, в xml–файле и загрузить его вместе со скриншотами. Это меня спасло.
Во время разработки я записывал, сколько времени и на что я потратил. На момент написания статьи:
- Программирование – 623 часа;
- Дизайн (3D модели, текстуры, иконка) – 60 часов;
- Objective–D – 234 часа;
- Маркетинг – 249 часов;
Это моя первая игра, так что времени на все можно было бы затратить меньше. Про маркетинг, например, я был вынужден прочитать множество информации, попробовать то, что не имеет смысла. Все равно, не могу понять, как получилось так много времени. Когда занимаешься маркетингом время утекает, а кажется, что ничего и не сделал.
Апрув занял 2 дня для Мак–версии и 5 дней для iOS. На данный момент цена $1.99. 15 промо–кодов для iOS версии можно получить здесь. Было бы очень интересно узнать ваше мнение. Я собираюсь улучшать игру и поэтому хотелось бы услышать, что бы вы улучшили в игре, что понравилось, что нет.
Знаю, что на Хабре любят читать также о маркетинге приложения. Разумеется это интересно, чтобы получить представление о прибылях, поучиться на чужих ошибках и успехах. Но сейчас об этом немного рано говорить, так как игра вышла совсем недавно. Думаю, выводы можно будет сделать примерно через месяц.
Скачать Raildale можно здесь.