Практичний досвід перенесення ресурсів з Flash у Unity 3D

Звичайно, першою ідеєю було спробувати AIR SDK – проект запустився, але з динамічної аркади він перетворився на аркаду "походову". FPS був дуже низьким через те, що майже вся графіка у флешці була векторною, а мобільний AIR з нею не дуже товаришує. Я вже не пам'ятаю точно, який AIR на той момент був доступний (2.x або перша версія 3.x), але ми проводили експерименти як з векторною графікою, так і з іншим проектом, зробленим у растрі на Flixel. Результати не дуже нас потішили. Зараз, я дивлюся, прогрес зрушив, Adobe навіть випустила якийсь новий компілятор. У будь-якому випадку, тоді було вирішено використовувати Unity 3D.
Unity 3D на той момент вже добре зарекомендувала себе у мобільних іграх і мала гарне візуальне середовище для створення ігрових сцен. Завдяки цьому можна було розділити безпосередньо програмування, підготовку ресурсів та дизайн ігрових рівнів та розподілити ці завдання з різних членів команди. Крім того, за родом основної діяльності я давно вже працюю з C#, тому з Unity я відчував себе комфортно.
Постало завдання, як перенести графіку та анімації (у тому числі складові) у новий проект.
Експорт графіки з Flash
Як відкрити SWF і перетворити векторні зображення на PNG або JPEG? Правильно! Потрібно використовувати Flash. Як зберегти отримані результати на диск? Правильно! Потрібно використати AIR.
Розтеризація була здійснена за допомогою BitmapData і PNGEncoder зподальшим збереженням у файл за допомогою FileStream.
Необхідно було побудувати процес таким чином, щоб анімації експортувалися з найменшими рухами тіла. А саме, щоб усі метадані (назви анімацій, розкадрування, масштаб кадрів, параметри зациклювання) можна було редагувати у середовищі Flash.
Adobe Flash не дозволяє додавати до MovieClip додаткову інформацію, тому довелося запровадити кілька угод. Наприклад, імена кліпів, які потрібно було експортувати, починалися з префіксу "e_". Цей префікс відрізався для формування підсумкових файлів. Для розмітки анімації та завдання її властивостей використовувалися мітки кадрів, задані у певному форматі. У результаті вийшов зручний синтаксис, а структура кожного експортованого MovieClip виглядала наступним чином:

На виході програми виходив набір спрайтлистів та їх опис у форматі XML. Кому цікаво, можуть покопатись у вихідниках. Вихідники непідготовлені, недокументовані, as is:). Просто ніколи зараз оформляти їх у "продукт", але їх можна розтягнути "на запчастини".
Окремо зазначу, що перегортання кадрів під час розтеризації у завантаженому ззовні MovieClip потребує “специфічних” прийомів. Це з поведінкою вкладених кліпів — можуть з'являтися кілька кадрів, потім зникати у процесі анімації. Тому для кожного нового проходу краще створювати об'єкт заново. Для отримання списку доступних кліпів у завантаженому файлі використовувалася бібліотека SWFExplorer.
Імпорт графіки в Unity 3D
Після того, як ресурси перетворені на нормальний для обробки вид, спрайтлисти з їх метаданими необхідно подати у зрозумілому для Unity форматі.
Ми вирішили не використовувати готові 2D-фреймворки під Unity,т.к. передбачалося обкатати технологію, отримати новий досвід та краще зрозуміти, як робити ігри в термінах цього середовища. Тому були придумані 2 спеціальні компоненти - AnimatedSprite і SpriteSheet.
Перший відповідав за власне виведення спрайту в ігровий простір. Він створював стандартні для Unity компоненти MeshFilter та MeshRenderer та наповнював їх даними зі SpriteSheet. Таким чином вдалося використати смачні фічі, а ля Dynamic Batching.

SpriteSheet ж містив посилання на текстуру, що підключається, список анімацій, кадрів та інші налаштування - всю ту інформацію, яка вивантажувалася з SWF. Вирішили зберігати її саме засобами Unity, щоб мати можливість коригувати параметри інструментами середовища. SpriteSheet'и генерувалися автоматично у вигляді готових префабів, які потім розміщувалися на сцені.
Результат роботи AIR-конвертера складався з png-і xml-файлів, тому на той момент найзручніше було розмістити код створення спрайтшитів у власному постпроцесорі імпорту текстур (AssetPostprocessor). Цей код перевіряв місцезнаходження файлу з текстурою та наявність поряд з ним xml-файлу з описом — у цьому випадку обробник генерував (або оновлював у разі переімпорту текстури) відповідні префаби та складав їхню відповідну папку.
Перші проблеми. Рівень із бомбою.
З першими проблемами ми зіткнулися, коли переносили бомбу – об'єкт, який знищує всіх ворогів на екрані. Спочатку ефект, з яким відбувався вибух, створював яскравий ореол на весь екран. Звичайно, при експорті розмір текстури почав перевищувати всі розумні межі. На порядок. До "кармаківських" мегатекстур ми ще не дорослі :), та й iOS тягне максимум 2048x2048.
З іншими об'єктами почали виникати схожі проблеми — анімації,у яких були різні напівпрозорі ефекти (спалахи, сяйва, арелої) починали займати просто величезне місце. Розмір кадру для одного стрипу (а в одному стрипі могло бути кілька анімацій) було фіксовано. Виходило, що один великий кадр розпирав всю анімацію, причому більшість текстури була заповнена порожнечею.
Першу труднощі дозволили просто вилучивши з анімації погані ефекти та замінивши їх на системи частинок Unity. Довелося писати додаткову логіку, але іншого виходу не було. Для другого випадку довелося додати поняття складеного SpriteSheet - це об'єкт, який веде себе як звичайний спрайтшит з точки зору внутрішньоігрового API, але насправді містить безліч інших спрайтшитів з окремими текстурами. При розмітці Flash-кліпу в мітках вказувалося, до якого складового SpriteSheet цей кліп належить. Таким чином, ми винесли всі великовагові анімації в окремі ресурси.
Висновок
Таким чином, ми отримали процес, який дозволяв в пару кліків отримувати з Flash готові для використання анімації. Звичайно, процес можна було зробити краще і правильніше, наприклад, я не знав на той момент про існування ScriptableObject — він краще підходить для цих завдань.
Я навмисно не став писати тут простирадла коду — будь-хто, кому потрібно вирішити схожу проблему, легко знайде всю необхідну документацію (я намагався навести тут посилання на матеріали, що використовуються). Нам поставлене завдання вирішити вдалося — ми отримали можливість легко використовувати векторні анімації, створені у Flash, готувати текстури для різних ігрових дозволів та багато бонусів. Звичайно, Unity 4 підкинув трохи дьогтю в бочку, але ці проблеми теж вирішуються.
А у нас тут можна отримати грант на тестовий період Яндекс.Хмари. Стоїтьлише у полі «секретний пароль» ввести «Хабр»