Наверное, многие слышали про проект Adobe Air — весьма здравая инициатива от компании Adobe сделать так, чтобы приложение на флэше могло компилиться и запускаться на любых платформах — десктоп, iOS, Android, телевизоры,…
Долгое время ничего толкового на air'е сделать было нельзя. Но в последнее время технология набирает обороты, Adobe внесла ряд оптимизаций в код air'a и теперь вполне можно написать на нем весьма шустрое приложение. В данной статье я расскажу о нашем опыте разработки air-приложения под iOS.
Как мы дошли до жизни такой?...
В данный момент основной проект (социальная игра) нашего маленького стартапа, фирмы в 3 человека — после года разработки заморожен на финальной стадии на время поиска инвесторов. Так что чтобы не сидеть без дела пока идет поиск/переговоры — нам пришло в голову сделать что-то не очень трудозатратное, а если оно сможет что-то заработать — так вообще шикарно.
Т.к. ни с unity, ни тем более с xcode никто из нас не знаком, зато со флэшом мы на «ты» — то пришла в голову мысль опробовать хваленую технологию Air для создания более-менее презентабельной и динамичной игры.
На данный момент use case'ов эира под iOS — пересчитать по пальцам. Да, Машинариум — неплох. Но, все-таки, — это не показатель. Нам было интересно, как air справится именно с динамичной игрушкой.
Итак, решение было принято. Примерный сроки (1 месяц) — поставлены. И мы сели копаться в новой для нас технологии…
Основной платформой, на которую мы ориентировались — был iPhone 4.
Идея игры.
Здесь мы долго не думали. Задачей было найти что-то, что бы подходило под следующие критерии:
- Простота => большая скорость разработки
- Отсутствие большого количества анимации, графики и т.п. (чтобы во-первых — не нагружать художника работой на пол года, а во-вторых — не нагружать процессор телефона)
- Желательно — незаезжанность темы
- Отсутствие необходимости создавать 100 сложных уровней-головоломок (что так же — замедлило бы разработку)
Придумывать что-то свое нам не хотелось, да и не на то был расчет. Так что мы начали бороздить интернет в поисках объекта клонирования.
После пары дней поисков — мы остановились на игрушке "Axe in Face". Она удовлетворяла всем нашим требованиям. Суть ее заключалась в том, чтобы рисовать пальцем траекторию полета топора и бросаться им во врагов.
Начало разработки.
Итак, мы начали… Стоит отметить, что представления о технологии Air — у нас не было совсем.
Но, как выяснилось — все совсем не страшно. Это тот же флэш, только с парочкой дополнительных классов для работы со специфическими для мобильных устройств функциями — мультитач и т.п.
Так что начали мы обычную разработку на флэше. Об этом писать не буду — это не тема статьи.
Расскажу лишь о проблемах и трудностях, с которыми мы столкнулись именно при запуске приложения на железе (iPhone, iPad).
Кстати, для тех, кто не понял, что такое Air — скажу в двух словах. Вы разрабатываете игру на флэше. Потом компилите ее под Air iOS и на выходе (в идеале) — получаете готовый .ipa файл для отправки в app store.
Для юзера, программа ничем не отличается от написанных на Objective C или Unity. Точно так же запускается на i-устройствах. Никаких дополнительных настроек или плясок с бубном — не требует.
Быстродействие.
Тема быстродействия — самая важная в нашей разработке. Естественно, нам хотелось получить продукт, который бы по плавности не отличался от других iOS-игр. Ну, или максимально к ним приближался. Обгоняя события, скажу, что это удалось не везде.
Итак, наша игра требовала вывод пары десятков анимированных спрайтов на экран как можно быстрее. Опишу технологии в хронологическом порядке.
Flash engine, bitmap frames.
Конечно же, ни о каком векторе речи быть не может. По этому первое, что мы попробовали — это экспортануть наш вектор в битмапки и вставить их обратно во флэш кадрами.
Получилось неплохо, но хотелось быстрее/плавнее.
Bitmap blitting.
Наверное, многие знакомы с этой технологией. Это случай, когда вы плюете на пайплайн флэша и делаете все сами — генерите пустой прямоугольник и каждый кадр, последовательно спрайт за спрайтом, с помощью copyPixels, копируете их на него.
Далее — выводите получившееся полотно как один Bitmap объект.
Эта технология неплохо себя показывает на десктопах, но на iOS она оказалась фейловой. Движок работал раз в 10 медленнее.
Модифицированный flash engine.
Вот она — золотая середина.
После некоторого гугленья, стало ясно, что позволяет ускорить графику. Суть в том, что когда мы как в 1-м случае делали каждый кадр анимации в новом фрейме — флэшу приходилось каждый фрейм убивать старый кадр из памяти и создавать новый. Что весьма ресурсоемко.
Где-то прочитал о технологии, которая позволяет выжать максимум из мобильного окружения.
Суть ее в том, что вы создаете MovieClip с 1 кадром и бросаете в этот фрейм ВСЕ кадры анимации сразу.
Далее, с помощью visible показываете только нужный. Фишка в том, что все кадры анимации одновременно присутствуют в памяти (и виртуальная машина уже выделила под них память и запихала их туда), а вы лишь включаете/выключаете их видимость. Но при этом не происходит перестроения памяти и все работает максимально быстро.
Как модификация технологии — есть вариант (который и использовали), когда все кадры хранятся в отдельных bitmapData. И вместо того, чтобы дергать visible у кучи Bitmap'ов, вы имеете один, основной Bitmap и переставляете ему bitmapData. Т.е. что-то вроде main_bmp.bitmapData = bd_frame[i];
На этом и остановились. Скорость анимации была где-то в 1,5 раза выше первого случая и позволяла выводить 20-30 спрайтов на 40 fps на iPhone4, что нас вполне устраивало.
Советы по оптимизации производительности.
В ходе разработки, мы столкнулись с граблями, которые хотелось бы просуммировать в виде советов:
- Как можно меньше создавайте динамичных объектов.
- Чем меньше объектов на экране будет ловить события «мыши» (пальца) — тем лучше. Ставьте всем mouseEnabled, mouseChildren в false.
- Лучше не пытайтесь двигать большие объекты и тем более — менять их альфу.
- Ставьте cacheAsBitmap для всего, что не анимировано.
- Если надо что-то вращать или менять альфу — юзайте cacheAsBitmapMatrix — это позволит ускорить этот процесс.
- Не вешайте кучу лисенеров на ENTER_FRAME. Лучше сделайте один, который будет вызывать все необходимые.
- Не привязывайтесь к кадрам, а привязывайтесь к таймеру. Т.е. в вашем лисенере на ENTER_FRAME ведите счетчик времени с прошлого вызова и уже исходя из него — производите все калькуляции.
Итак… В сроки мы не уложились и вместо 1 месяца, ушло на все 2. Но очень уж не хотелось выпускать совсем какашку.
Специфика платформы.
Retina vs lo-res.
Как ведет себя air-приложение, запущенное на айфонах с разным экраном? На самом деле, все просто. В настройках вы выставляете, хотите вы ретина-приложение или нет. И в зависимости от этого — ваше приложение будет масштабироваться.
В нашем случае, мы создали ретина приложение и размер сцены 960x640. На iPhone 4/4S оно идет без масштабирования. На 3-й серии оно скейлится на 50%.
Конечно, при большом желании — можно заморочиться и получать scale при инициализации и в зависимости от того, будет ли он 1.0 или 0.5 — выводить разную графику… Но это показалось нам очень сложным (да и не позволило бы собрать сцены в самом флэше, все бы пришлось писать кодом), так что мы плюнули.
iPhone vs iPad.
Тут тоже самое, что и с ретиной. Если вы выставите галочку «iPad», то приложение на айпаде будет запускаться во весь экран, масштабируясь под него (что в случае 960x640 приведет к некратному масштабированию и артефактам). Если же такую галочку не ставить — то оно будет вести себя как обычное iPhone-приложение, запущенное на айпаде — т.е. запускаться в малекьном окошке с кнопкой «х2».
Мы сделали именно так.
В последствии, вероятно, соберем HD версию специально под айпад — на полный экран и с полноценной графикой.
CPU vs GPU.
Флэш под Air можно собрать в двух вариантах — с движком на GPU и на CPU. К моему удивлению, алгоритм движка был такой, что разница между GPU и CPU была очень незначительна (не более 10%). По этому, мы остановились на CPU, т.к. компиляция под GPU не поддерживает эффектов. Т.е. все обводки шрифтов и тенюшки не работали бы. Конечно, выход был — брать шрифт с эффектами, создавать bitmapdata, туда делать draw() этого шрифта, а полученный битмэп — уже добавлять на сцену. В таком случае, все эффекты были бы на месте, т.к. draw() выполняется в любом случае на CPU и по этому не теряет эффектов.
Но это было как-то очень геморно и было решено, что игра не стоит свеч.
Но, думаю, этот вопрос надо рассматривать индивидуально, для каждого проекта.
Проблемы и решения.
Очевидно, не ко всем возможностям iOS мы будем иметь доступ из Air. Например, к возможностям Game Center. Что делать? Тупик?
Вовсе нет. Для всего подобного есть технология native extensions. С помощью этих расширений можно «достучаться» до любого специфичного железа. Как их использовать — тема довольно обширная.
Кроме того, использование native extensions влечет вторую (и даже третью) проблемы — невозможность скомпилить ipa из флэша (необходимо пользоваться командной строкой) и танцы с бубном чтобы это дело заработало на железе.
Также, почему-то новые версии Эира плевать хотели на выключатель звука на телефоне. Чтобы он заработал — тоже нужно воспользоваться native extension'ом. Если будет интересно — могу написать отдельную статью про native extensions.
Плюс ко всему, весь процесс все равно нельзя завершить на PC. Несмотря на то, что даже сертификаты можно создать под windows (опять-таки — если кому интересно — могу описать все пляски с бубном в отдельной статье), но чего нельзя сделать под виндами — это залить приложение в апп стор. С недавних пор — это делается единственным возможным путем — с помощью специальной программы, которая требует минимум Mac OS 10.6.8. И никак иначе. Долгая и упорная пляска с бубном таки позволила поставить эту версию макоси на виртуалку под AMD (если кому интересно, то коротко: работал только образ 10.6.4 (legacy), на него скачал комбо-апдейт до 10.6.8 (руками!), поставил, не ребутил, заменил kext'ы чтобы не висло на PCI configuration begin, загрузил с игнорирование кэшей). Еще немного плясок с бубном — и приложение залито!
Выводы.
Удался ли опыт? Как именно опыт новой технологии — я считаю, да.
Но как платформу для написания динамичных игр — я бы все-таки пока что не советовал флэш. Т.к. тормоза все-таки есть. Например, анимацию передвижения объектов в меню так и не удалось сделать плавной на 4-м айфоне. На 4S и iPad 2 — все летает. Но, с другой стороны, — эти особенности не особо критичны и не мешают геймплею.
Резюмируя — можно сказать так — писать можно. И даже выглядеть это может неплохо. Но по некоторым пунктам все равно пока не дотягивает до нативных приложений.
Хотя, Adobe тоже не стоит на месте. Вчера он анонсировал релиз-кандидат Air 3.2, где есть полное использование GPU (в т.ч. и 3D). Посмотрим…
Результат.
Здесь были картинки, промо-коды и ссылки на продукт, но т.к. я не хочу публиковаться в «я пиарюсь», то я убрал их.
О результатах пока говорить рано — игрушка только несколько дней в аппсторе. Недавно опубликовались на iphones.ru. Так что пока что — все впереди. Если будет интересно — потом могу написать о коммерческих результатах. Правда, уже словили отзыв на 1 балл от «героя», жалующегося на отсутствие ачивок (а они есть, и прямо в главном меню) и физики. Да, именно физики у нас в игре и не хватает.
Как бонус — пара скетчей:
Автор: soulburner
soulburner, хотелось бы лично поговорить с вами если это возможно. напишите на coool-of-cold@yandex.ru
soulburner, есть предложение по инвестированию и разработке приложений