Растеризация графики во Flash

Векторная графика хороша, пока её не становится много :] Когда её становится много, то процессор начинает не выдерживать нагрузки и игра начинает заметно тормозить. На помощь приходит растеризация векторной графики!

Есть 2 пути растеризовать векторную графику: перевести всю графику в растровые аналоги (например в .png) или же растеризовать вектор программно.

В этой статье мы рассмотрим второй вариант — программную растеризацию.

Мои наработки основаны на 3-х классах Антона Карлова, о них он пишет в своей статье «Из вектора в растр».

В своей версии я изменил и дополнил по большей части классы AnimCache и Actor.

Рассмотрим все классы подробнее.

Классы модуля

Первый класс MaxAnimCache — это хранилище всех растеризованных клипов. Он выполняет процесс кэширования любых указанных клипов и хранит результаты своей работы, пока не будет очищен. Можно создавать отдельные экземпляры класса, для разных блоков графики.

Методы класса MaxAnimCache
cacheAnimClipFromLib(clipClass:Class):MaxAnim Выполняет кэширование указанного клипа, заносит его в хранилище и возвращает результирующую анимацию.
cacheAnimFromDisplayObj(aObj: DisplayObject, aKey: String): MaxAnim Выполняет кэширование DisplayObject-а, можно указать ключевое имя для него. Возвращает результирующую анимацию.
cacheAnim(aKey: String, aAnim: MaxAnim): MaxAnim Заносит указанную анимацию в хранилище.
cacheSpriteFromAddr(aAddr: String, aIsLocalLaunch: Boolean): MaxAnim Кеширование изображения прям из указанного адреса. Нужно указать, флешка запущенна локально или нет.
getAnim(key:String): MaxAnim Извлекает копию анимации из кэша по идентификатору.
addClipToCacheQueue(clipClass:Class):void Добавляет имя клипа в очередь для кэширования. clipClass — имя класса клипа, которое необходимо растеризовать.
addClipsToCacheQueue(clipClasses:Array):void Добавляет несколько имен клипов в очередь для кэширования. clipClasses — массив классов.
makeCache():void Запускает процесс кэширования.
isAnimAvailabe(aKey: String): Boolean Есть ли такая анимация в коллекции?
clear():void Очищает хранилище.

Второй класс MaxAnim — это класс самой анимации, он является хранителем всех кадров конкретного клипа. Все кадры внутри класса хранятся в публичном массиве frames в формате BitmapData. Так же в этом классе находятся методы для преобразования векторного клипа в растр. С помощью этого класса можно локально растеризовать какие-либо отдельные клипы с целью взять растеризованный результат.

Методы класса MaxAnim
cacheFromLib(clipClass:Class):void Кэширование клипа из библиотеки. clipName — Имя класса клипа в библиотеки клипов.
cacheFromClip(clip:MovieClip):void Кэширование из экземпляра клипа. clip — клип который необходимо растеризовать.
 cacheFromDisplayObject(aObj: DisplayObject):void  Кэширование из экземпляра DisplayObject.
 cacheFromAddress(aAddr: String, aIsLocalLaunch: Boolean):void  Кэширует картинку из указанного адреса.
 cacheFromAnimAtlas(aObj: DisplayObject, aW:Number, aH:Number):void Кэширование графики спрайтового атласа с автоматической разбивкой на кадры.
 clone():MaxAnim Создает новый экземпляр анимации эдентичный текущей.
 clearFrames():void Удаляет все кадры

И последний класс MaxActor — это класс графическая сущность, которая занимается воспроизведением и рендером растровых анимаций. Это тот самый класс, который идет к вам на замену векторных MovieClip. Этот класс унаследован от Sprite и имеет такие же методы, как у MovieClip для работы с анимацией. То есть фактически, используя этот класс, вы работаете как самым обычным MovieClip, но лишь с той разницей, что вся графика внутри него растровая.

Рассмотрим основные методы.

Методы класса MaxActor
addAnim(anim: MaxAnim, uniqueName: String = null, switchToAnim: Boolean = false):void Добавляет новую анимацию с возможным указанием имени и флагом переключиться ли сразу на эту анимацию.
addAnimFromCache(aCache: MaxAnimCache, key: String, uniqueName: String = null, switchToAnim: Boolean = false):void Добавляет новую анимацию из кэша анимаций.
switchAnim(animName:String, aPlay: Boolean = false):void Переключается на заданную анимацию.

Остальные методы вы можете посмотреть в коде, большая часть прокомментирована.

Вся разница в том, что я значительно дополнил класс Actor-а, а так же выделил AnimCache из синглтона в обычный класс, что позволяет указывать при создании MaxActor определённый AnimCache. Можно, например, создавать отдельные AnimCache для меню и для игры и кешировать в игровой клипы лишь при необходимости, что разгружает оперативную память, а если ещё учитывать именно те клипы, которые будут использоваться на уровне и не кешировать другие, то вообще супер.

Давайте посмотрим на 2 идентичных проекта. Отличия будут только в том, что во втором мы будем применять растеризацию графических объектов.

Я не буду выкладывать оба проекта в статью, т.к. FPS будет зависеть от других флешек на этой же странице. Поэтому я сделал их на отдельных страницах, чтобы вы смогли сами посмотреть и потестировать FPS.

В первом случае используем векторные изображения: Тест без растеризации.

А во втором случае те же самые векторные изображения растеризуем тем способом, который я хочу вам представить: Тест с растеризацией.

Рассмотрим код первой программы. Он состоит всего из 2-х файлов: главного и объекта, который создаётся и летает по сцене.

Основной файл Main.as

Тут в целом всё должно быть понятно, тем более есть некоторые комментарии.

Рассмотрим класс объекта.

Класс объекта Ashigaru

Коротко опишу логику класса.

В констуркторе сразу создаются все клипы анимаций, которые затем проигрываются случайным образом. Клип _curr является ссылкой на клип, который отображается в данный момент. В функции update() происходит вся логика перемещения, вращения и смены анимации по её завершённости или по таймеру базовой статической анимации.

В общем про код первого теста достаточно сказать, что отображение и анимация в нём сделана обычными способами с векторной графикой.

Куда интереснее рассмотреть код второго теста, посмотреть как именно он изменился и подойти к организации растеризации.

Главный класс Main проекта с растеризацией

Обратим внимание на изменение инициализации. В самом начале создаётся класс MaxAnimCache, это хранилище всех растеризованных клипов, которые мы укажем атрибутом в массиве для функции .addClipsToCacheQueue(), после этого указываем калбэк-функцию завершения кэширования и запускаем процесс кэширования анимации. Так же можно указать калбэк-функцию которая будет вызываться в процессе кэширования — .onProgressCallback. Пригодится, если у вас много клипов для кэширования и вы хотите как-либо отобразить этот процесс.

Далее по завершению кэширования выполняется калбэк-функция onCacheDone() и мы можем продолжать инициализировать игру.

Таким образом создаётся предкэширование всей необходимой графики и анимации. Например я сделал кэш игровых объектов, а GUI оставил векторным, т.к. его нагрузка не существенна.

Ещё изменился конструктор объекта, теперь в него необходимо передать наш банк кэша, чтобы использовать кэш уже в классе объекта.

Класс объекта Ashigaru с растеризацией

Сам класс Ashigaru будет выполнять роль контейнера, а для отображения кэшированных клипов используется класс MaxActor. Он создаётся сразу в конструкторе и в него добавляются анимации функцией addAnimFromCache(банк анимаций, имя закэшированного клипа, имя анимации). Переключать анимации в MaxActor будем функцией switchAnim(имя анимации), а отслеживать окончание анимации с помощью указания события onCompleteCallback.

Вся логика данного кэширования заключается в 3-х классах: MaxAnimCache, MaxActor, MaxAnim.

Скачать примеры: архив с примерами.

На этом пока всё, но продолжение следует (напишу про рендер в 1 битмап).