05 августа 2011

Flash: некоторые проблемы и их решения...

Наверно стоит начать это сообщение с того, что еще год назад я активно делал игру на Delphi, стремясь продать свой первый казуальный проект. Но уже тогда, читая форумы и блоги о flash-индустрии компьютерных игр, мне хотелось попробовать себя в этом направлении... В общем, сейчас проходят предрелизные проволочки с первой flash-игрой, которую мы снова с leric сделали "на пару". В итоге я узнал много интересного, пришлось изучить новые технологии, новые инструменты и редакторы. И вместе с тем пришлось продираться через дебри неясностей, проблем и всяких багов.
Сегодня решил описать некоторые момента, которые иногда выводили меня из себя, ведь казалось бы все прозрачно и понятно, но нет ведь, не работает!
На повестке дня у нас получается вот такой список:
  • не отвечали клавиши в игре
  • прелоадер
  • тормоза в IDE
  • встраивание шрифта внутрь флешки
  • растеризация мувиков
  • CPMStar

Итак, пойдем по порядку...

Не отвечали клавиши в игре
О, интересный баг-фантом... Дело было так: leric играет в игру и говорит "что-то пробел не всегда срабатывает" ... я удивляюсь - "не может быть!" Играю сам, и не разу не попадаю в позицию, когда бы у меня не сработала какая-либо клавиша. Ситуация еще осложнилась тем, что я добавил фичу, по которой появился индикатор, ознаменующий, что реакции на клавишу пробел сейчас не будет, то есть действие в данный момент недоступно. И я грешил на то, что у leric как раз нажатие пробела приходилось на недоступность операции. Прошло несколько дней, жалоб стало больше, а я все никак не мог понять в чем дело. И тут случилось счастье - у меня тоже не сработал пробел! Я начал нажимать все клавиши подряд, пробовать комбинации и сочетания клавиш и пришел к выводу, что нажатие трех кнопок - "вверх+влево+пробел" не отрабатывает должным образом... Нехитрые debug-индикаторы показали, что это происходит где-то снаружи, где-то в недрах flash'а!
В общем, спросив на форуме я получил ответ, что проблема не решаема в рамках кода, и нужно просто переназначать клавиши. Проверить работоспособность тех или иных сочетаний можно здесь. Проблема интересная, фантомная и вообще не очень приятная. Хорошо, что узнали об этом сейчас, а не на стадии распространения :)

Прелоадер
Что мы видим при запуске игры? Любой - флеш, консоль, он-лайн... Мы смотрим заставки, сплэши, прелоадеры и остальное... Почему? Все просто - чтобы загрузить ресурсы игры незаметно от игрока. Он вроде бы смотрит картинки, рекламу разработчиков и издателей, сменяющих друг друга, а в это время компьютер напряженно располагает текстуры в видеопамяти, закачивает остальную флешку или же строит уровень из каких-то данных.
Ну так вот... сделал я этот прелоадер, все работает, все отлично... Но после каких-то изменений, касающихся вставки сплеша спонсора, прелоадер перестал выполнять свою функцию - он начал появляться уже после того, как флешка загрузится. Выглядит это так: белый экран на 5-10 секунд, а потом появляется флешка с надписью гласящей "все загружено, играть?" Ужас! Тормозил и нервничал я недолго, но очень сильно. Спонсору я бы должен отправить готовую игру с его брендингом еще вчера, а я сижу, откатываюсь по версиям, и пробую разобраться в чем же дело.
Оказалась проблема в том, что я в прелоадере использовал явное приведение типов к главному объекту игры. Нужно это было для того, чтобы стартовать звук в нужный момент. Решение было неудачное, так как объявление класса игры в прелоадере повлекло за собой загрузку всех данных раньше, чем им положено. В итоге мораль - ни в коем случае не используем классы и объекты игры в прелоадере, это до добра не доведет. А у меня все решилось одной посылкой события "запускай звук", которое ловит главный объект игры после загрузки всех данных.

Тормоза в IDE
Жуткая жуть создавать головоломистые уровни для игры, когда тормозит редактор, в котором ты собственно все и собираешь. Передвинул объект - подождал полсекунды, повернул декоративный спрайт - подождал еще секунду. Это было невыносимо.
Лично у меня каждый уровень - это отдельный кадр клипа Levels. И недавно выяснилась одна простая вещь - если в том же fla-файле создать новый символ под уровни, то тормоза прекращаются. Я почему-то думал, что тормоза идут от большого количества объектов в файле, а оказалось на подтормаживание программы влияет количество объектов в конкретном клипе, считая все его кадры. Момент интересный, и теперь у меня появились символы Levels_1_5, Levels_6_10 и т.д... То есть храню всего лишь по нескольку уровней в одном клипе, а не все сразу. И ничего не тормозит :)

Встраивание шрифта внутрь флешки
При использвании нестандартного шрифта в играх, необходимо озаботиться тем, как отображение будет работать на компьютере, где такой шрифт не установлен в системе.
В моем случае достаточно воспользоваться вот такой магической строкой:
[Embed(source = "k:/myfont.otf", fontName = "MyFont", fontWeight = "normal", embedAsCFF = "false")]  public static var EmbedFont:Class;

и теперь шрифт встроится во флешку и его можно использовать в любом месте, украшая игру красивыми надписями. Изначальная проблема была в том, что я вбил в fontName тоже имя, что и самого шрифта. Думал, что имеется ввиду имя шрифта в файле, а не то, как он будет виден программе.
Из-за этого вылезали всякие ошибки или просто текст не появлялся на экране. Когда догадался указать произвольное имя MyFont, все заработало!

Растеризация мувиков
О-о-о, на эту тему можно найти целые статьи и ветки форумов. Вещь не очень простая, но зачастую сильно повышающая фпс. В общем, всем флешерам-игроделам рекомендую взять на заметку. Особенно растеризация хороша для статических объектов. Дело в том, что постоянная отрисовка векторных объектов может быть намного более затратной операцией, нежели попиксельный вывод растеризованной картинки! Поэтому во время загрузки уровня можно растеризовать векторные игровые объекты в обычные битмапы. Единственное, при поворотах таких картинок, могут появляться артефакты изображения; поэтому для динамических объектов растеризацию я почти не использую, оставляя объект векторным. В двух словах можно выразить схему растеризации так:
BitmapDataObject.draw(VisualObject, VisualMatrix);
То есть по сути мы берем наш VisualObject и рисуем его на BitmapDataObject: BitmapData, после чего оперируем уже с растеризованным объектом, проще говоря - картинкой!
Но появляется проблема при заполнении матрицы VisualMatrix. В общем, я сам пока не учел все тонкости при растеризации, поэтому лучше расскажу об этом отдельно, постаравшись захватить все детали этого нелегкого дела.

CPMStar
Ну и немного об одном из способов монетизации игры. Можно воспользоваться какой-нибудь баннерной сетью и встроить в свою игру рекламу. При каждом клике по такому баннеру разработчику приходят деньги. На самом деле там всего пара центов, но все же. Хитовые игры могут прилично заработать на таких рекламных баннерах. В общем, и я решил изучить как там и что, зарегистрировался на CPMStar и попробовал встроить рекламу в свою игру. По сути там все просто - после регистрации можно скачать даже пример использования API этой самой баннерной сети. Единственное, что придется поменять - это id вашей игры, чтобы деньги начислялись куда надо. Так вот у меня самая большая проблема была в том, как добавить игру в систему, чтобы моей игре выдали этот самый id. Сначала я попробовал автоматически получить id через FGL после торгов за игру, и вроде все прошло успешно, но в моем аккаунте CPMStar никаких изменений не произошло, показалывалось, что ни к одной моей игре не привязана рекламная сеть. В общем, пришлось списываться со спонсором и просить его утвердить мою игру в CPMStar-системе на выдачу мне id. Так что использовать напрямую FGL для таких целей я больше не буду, мутно как-то.
Возможно, вся эта система выглядит мудреной, и, скорее всего, так оно и есть, но, если нужны деньги - приходится изучать все это и по мере надобности искать обходные пути :)

В общем, разбавил свои последние delphi-заметки, флешовыми тонкостями. Надо быть разносторонним, так что буду стараться и впредь, как говорится!

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

Сообщения, схожие по тематике:

4 коммент.:

  1. Полгода назад мельком изучал флеш и даже написал простенькую игру. Честно говоря, не очень понравилось с ним работать, все время возникает чувство, что забиваешь гвозди не микроскопом, но телефоном точно. Неинтуитивная архитектура - мувиклипы, символы.

    Правда, мое знакомство длилось одну ночь, как раз перед сдачей лабораторной по флешу, соответственно 250 страниц мануала было скурено за три-четыре часа, поэтому мое мнение вряд ли компетентно.

    Куда думаешь двинуться на этот раз? Флеш, делфи+сцена, делфи+что-то иное?

    ОтветитьУдалить
  2. По поводу клавиш - создание своего класса, наследованого от EventDispatcher(или его наследников) и в собыитии ENTER_FRAME регистрирующего IsKeyDown, обычно спасает от таких пробелм. Загрузчик - обычно, как ты и написал, проблемы доставляет при корявой организации струкутры игровых классов. Если нужно делать загрузку крупной флешки + в ней еще чего-то грузить - обычно использую флешку-контейнер, в которой через Loader загружается игра, в ней на событие добавления на сцену вешается слушатель - запускать свою загрузку(построение уровня, игровой процесс, или что там нужно). Но тут уже появляются проблемы с безопасностью, файлами crossdomain...Блин, надо уезжать куда-то в деревню, подальше от этих компов :)

    ОтветитьУдалить
  3. 1) Почитай про устройство клавиатуры, там несколько секций, каждая из которых не может передавать более 3 нажатий. Проблема уровня железа (древние компы пищали при таком зажатии воще )
    2) Прелоадер не должен использовать тяжёлые игровые package (и те что с ними в зависимости) хранящие твою графику, также не должно быть аналогичного импорта в internal секциях )
    4) Ещё здорово указывать unicodeRange для уменьшения размера флешки.
    5) Чтобы уменьшить артефакты при поворотах растра, нужно включать smoothing (билинейная фильтрация) для Bitmap. А вообще у мувиклипов есть свойство cacheAsBitmap )

    ОтветитьУдалить
  4. "В итоге мораль - ни в коем случае не используем классы и объекты игры в прелоадере, это до добра не доведет. А у меня все решилось одной посылкой события "запускай звук", которое ловит главный объект игры после загрузки всех данных."

    А код можно опубликовать?

    ОтветитьУдалить