Я не являюсь профессиональным разработчиком программного обеспечения и программирование практически никак не связано с моей основной трудовой деятельностью. Все гораздо хуже — это мое хобби. Смена деятельности весьма полезна и позволяет отдыхать от унылой и монотонной работы, а если она еще и позволяет извлекать удовольствие от процесса и результата, то это полезно вдвойне.
Для меня всегда интересным был gamedev (game development — разработка игр). Думаю, у каждого ребенка (подростка, гика, подставить свое) была такая пусть далекая и практически недостижимая, но мечта. Большинство вырастают и благополучно забывают о ней под грузом текущих проблем, а некоторые сохраняют ее даже до того момента, когда их дети вырастают и сами начинают мастерить что-то подобное. Мне повезло (или не повезло) относиться ко второй группе.
Предыстория
Можно долго рассказывать о том, как проходило становление меня как gamedev-разработчика — это все скучно, утомительно и не интересно. Могу сказать только, что периодически натыкаясь на то, что делал ранее, не устаю поражаться тому, насколько много было дикой энергии и усидчивости на изобретение собственных «велосипедов», причем порой они были красивы и работали на грани понимания. С годами приходил опыт, накапливались специфические знания, все больше прогрессировала лень. Было много разнообразных попыток сваять свой игровой движок (думаю, через это проходили все более менее продвинувшиеся дальше HelloWorld-ов). Метания между GAPI (DX7/8/9, позже были потуги под OpenGL 1.1/2.1), языками программирования (C++, C#). Впрочем, дальше реализации рендера и графа сцены все это обычно не заходило — самомотивация весьма ненадежный союзник. Шло время, были перепробованы opensource-движки, мысли о написании чего-то своего с переменным успехом загонялись поглубже.
Выбор движка
И тут случайно подвернулся unity3d. К тому времени я уже совсем обленился и соглашался что-то писать исключительно на C# (на нем просто приятно писать, в отличие от той же явы). Поразила сама система компонентного подхода для расширения функционала унифицированного объекта, а уж про удобную интеграцию окружения дизайнера и окружения разработчика в одном флаконе и говорить нечего. Главный же конек unity3d — это скорость и возможность работы на множестве платформ без каких-либо усилий со стороны разработчика. Да, возникает необходимость мелких адаптаций, но на других движках вообще мрак.
Команда
Как один в поле не воин, так и программист много в одиночку сделать не сможет, тем более, если он не умеет рисовать с достойным качеством. Было очень много попыток найти адекватных людей для разработки, но большинство требовало денег (чего у indie-разработчика нет в принципе) без согласия на долевое участие, остальные мало что из себя представляли как специалисты в своих областях. И тут мне несказанно повезло. Через знакомых знакомых вдруг обнаружился художник, который сам искал программиста и точно так же не мог найти. В результате получился тандем о процессе сотрудничества которого и результатах будет написано далее.
Целевая платформа
Полигоном для издевательств разработки был выбран Android: небольшая цена для выхода на market (теперь уже google play), низкий порог входа, да и мобильный рынок для актуальных железок, что может быть интереснее?
Проект
Или проЭкт, каковым он был, да и сейчас остается. Сразу скажу, что никаких временных планов по разработке у нас не было, роли не были разграничены в принципе, все делалось на авось в остатки свободного времени вечерами и не каждый день. Звучит страшно, но это работало и работает в силу малого количества людей в команде, быстрого согласования действий через скайп и регулярного взаимного подпинывания. Так как мы никогда не работали вместе, было решено выбрать что-то попроще. Выбор пал на детскую сказку «Колобок». Кому-то станет смешно от нашей неосведомленности о кухне детских книжек на мобильных устройствах, но нам тогда показалось, что это просто, интересно и позволит наладить рабочие отношения.
Простую сказку-книжку делать скучно, поэтому было решено сразу же сделать ее интерактивной: задача ребенка была тыкать пальчиком в экран, задача книжки — давать фидбек на касания и развлекать ребенка. Фактически, это было все ТЗ на проект.
Каждый из нас обладал определенными знаниями в своей области и уже представлял, как и что будет выглядеть. Художник умел рисовать только в 2D (но делал это хорошо), спорить мы не стали, а обговорили данные, которые я получу от него. Весь арт изначально делался в CorelDraw и частично анимировался (где требовалась нелинейная анимация) в Flash-е. На выходе мне передавалась россыпь спрайтов в png с альфой и картинка-превью, как все должно было выглядеть по мнению художника. Собирать все это, оживлять и заставлять взаимодействовать с пользователем пришлось мне.
Надо сказать, что unity3d — это полноценный 3d движок без малейшего намека на обычный 2d. На маркете компонентов для unity3d (да, есть и такой) существует штуки четыре основных систем по реализации спрайтов. Все они стоят денег, а как было сказано ранее, я лучше сделаю свое, чем куплю, будет эдакий challenge. Все спрайтовые системы реализуются просто: две оси определяют плоскость экрана, третья ось становится глубиной для спрайтовых слоев. Спрайты — это плоскости, перпендикулярные камере с наложенной текстурой.
Звучит просто, но на самом деле следует учитывать одну особенность — очень слабое железо мобильных устройств. Есть такое понятие как количество drawcall (далее — дк) (или drawindexedprimitives / drawelements, во что это все транслируется внутри в процессе рендера) — каждый объект рисуется отдельным вызовом графического апи. Все просто, но проблема в том, что если на десктопе количество таких отрисовок может до 1000 и относительно современное железо не поперхнется, то для мобильных устройств это значение следует держать в пределах 20. Всего 20 дк! Слава богу, в юнити существует автоматическая система батчинга (batch — выполнение одной операции над множеством однотипных данных, фактически подготовка данных для SIMD) — unity3d самостоятельно сортирует геометрию по материалам (уменьшается количество переключений текстурных блоков), объединяет геометрию в большие накопительные вертексные буферы, которые уже потом отрисовываются за один раз для каждого материала. В результате если у вас одна текстура, допустим, шишки и вы размножите этот спрайт, то unity3d соптимизирует все эти спрайты в один дк.
Второй способ оптимизации — создание текстурных атласов — чем меньше материалов будет, тем меньше будет переключений текстуры и тем меньше будет дк. Арта у нас было много и он постоянно менялся — была написана утилита по генерации атласов текстур, причем это было сделано внутри редактора unity3d как расширение самой оболочки. Весь арт был рассортирован по сценам, общий дня нескольких сцен был вынесен на отдельный атлас. Теперь при изменении арта я просто натравливал утилиту на папку с содержимым будущего атласа (все спрайты, включая все фазы анимации) и на выходе получал одну единственную текстуру + файл-описание размещения спрайтов внутри этой текстуры (имя кадра, координаты зоны в картинке, скорость анимации, тип анимации — линейная / флип-флоп и т.п.).
Сам рендер был прост: вся геометрия была процедурной и перегенерировалась при смене кадра анимации (вершинные и текстурные координаты). В результате всех этих ухищрений некоторые сцены книжки рисуются за 4-5 дк, не бьют по производительности (работают хорошо даже на смартфонах, а не только на планшетах) и выглядят хорошо.
Пока все это разрабатывалось, обнаружилось 2 неприятные особенности:
- бейте художника по рукам, если он использует плавные градиенты — они ужасно выглядят в аппаратно поддерживающиеся форматах сжатия типа DX1/5 и т.п. В нашем случае все текстуры пришлось перевести в полноценные 32-битные текстуры-атласы 1к х 1к — можете представить, как оно сказалось на оперативной памяти и филрейте.
- если вы будете масштабировать спрайты знайте, что автоматический батчинг не работает на масштабе, отличном от Vector3.one. Это очень важно для оптимизации, у нас было много объектов, отличающихся друг от друга размерами и отзеркаленных по осям — для них пришлось делать дополнительное запекание масштаба в геометрию и сброс масштаба в единицу. Для динамики такое не подошло в силу значительного усложнения кода — пришлось смириться и использовать по-минимуму.
Многообразие устройств
Меня не сильно пугал весь зоопарк устройств на платформе Android. Изначально практика pixel-точных игрушек была принята порочной и убийственной для разработчика / художника — у нас нет таких мощностей, чтобы подготовить несколько пакетов графики под разные dpi и соотношения сторон. Все разрабатывалось только под один типоразмер — 1024х600, альбомная ориентация. Все, что не попадало под эти размеры, автоматически масштабировалось под виртуальную камеру unity3d и становилось высотой в 600 виртуальных единиц, ширина так же сохраняла пропорции и практически всегда была больше реального размера экрана, обрезаясь краями (что нас устроило — просто отодвинули важные объекты от краев). Практически, потому что появилась возможность протестировать прилоежние на «Experia P» — там ширины в 1024 пиксела не хватило и по краям остались полоски. В качестве варианта, устроившего всех, было решено немного растягивать фон по ширине (коэффициент 1.05) — это незаметно глазу и устраняет полоски на слишком длинных экранах.
Озвучивание
Озвучивание сразу же было заказано у профессионального диктора — тут вообще без обсуждений все прошло. Пришлось потратить деньги (единственная затрата), но получить на выходе хороший результат, который с небольшими допиливаниями сразу пошел в релиз, благо вся программная часть была уже подготовлена и протестирована.
Подготовка к публикации
Вся разработка и тестирование происходили в среде unity3d + делались сборки для webplayer-а. Для сборки под Android необходимо 2 вещи: android sdk с установленными необходимыми платформами и лицензия unity3d для Android. Unity3d позволяет собирать под различные версии Android-а, основной была выбрана 2.2 из-за возможности переноса на SD-card. Лицензия для публикации становится проблемой для indie-разработчика, ведь у него еще нет никакого дохода с проекта, но благодаря аттракциону невиданной щедрости, проходившего несколько месяцев назад, я стал обладателем лицензии совершенно бесплатно для себя.
Публикация
Никогда не думал, что будут такие проблемы с публикацией — во всех статьях пишут, что все происходит быстро и безболезненно. На самом деле у гугла несколько серверов, синхронизация данных между которыми происходит очень медленно. Т.е. можно отредактировать данные приложения, залить новый apk и увидеть на странице описания старый текст / старый дистрибутив, а выйдя на страницу категорий приложений — увидеть там что-то еще (если правили несколько раз). Вся эта каша приводится к одному виду примерно через час-полтора.
Реклама
Мы этим не занимались в принципе — я написал мини-обзор (фактически, рекламный анонс) на пару ресурсов и на этом успокоился. Мы были готовы к тому, что детские книжки, да еще на Android, да еще и на русском — это не сильно востребованный товар, поэтому глупо ждать каких-то значимых прибылей. Так же было подмечено, что люди не любят платить в принципе и любят гадить в комментах у бесплатных версий приложений, придираясь по мелочам, что негативно сказывается на рейтинге приложений. Было принято волевое решение — делать только платную версию по средней цене. Плата стала эдаким входящим порогом, защищающим нас от троллей. Это дало волшебный эффект: за 4 дня мы собрали 4 отзыва на 5 баллов и один на 4 балла, что подняло нас на 13 место в своей категории и на 17 место в общем топе новых платных приложений. И это при 56 проданных копиях на текущий момент и 5 комментариях! Мне не понять, как они считают рейтинги, но мы в топе и это не может не радовать.
Те, кто не хотел платить, бесновались на ресурсах с пиар-статьями, были угрозы, что будут ломать и воровать, но рейтинг они нам не испортили.
Итог
Стоит ли становиться геймдевелопером? Это каждый решает сам для себя. Больших прибылей на паре проектов тут точно не получить, но при постоянной работе и непрерывном производстве можно вылезти (только это уже будут не indie-команды). Будьте уверены, что команда без хорошей теоретической и практической подготовки в разных областях долго не протянет — каждый участник должен давать что-то свое, становясь частью успешного монолитного решения.
З.Ы. Старался не писать заумных слов, чтобы было понятно большинству, извиняйте, если что.
Автор: Leopotam