Реализация пиксельных эффектов средствами Flash 8

Пример практического применения попиксельного считывания и рисования.

В статье нет полного описания приведенного примера и нет исходников — они еще далеки от совершенства и требуют оптимизации производительности. Здесь приводятся общие соображения по реализации подобных вещей.

назад к списку уроков и рецептов

1. что получилось

2. как сделано

3. тормозит. :( как с этим бороться?



1. Что получилось

Ролик, демонстрирующий пиксельные эффекты с символами шрифтов.

в начало

2. Как сделано

Эффекты такого рода реализуются с помощью класса flash.display.BitmapData, доступного в Flash 8. Я выбрал такой путь: сначала собираются данные о символах шрифта, а затем из этих символов составляется требуемая строка.

Принципиально здесь нет ничего сложного:
  • Собрать информацию о пикселях символов шрифта (методы BitmapData.getPixel() и BitmapData.getPixel32()).
  • Из символов попиксельно нарисовать строку (методы BitmapData.setPixel() и BitmapData.setPixel32()).
  • Перемещая пиксели, перерисовывать получившуюся картинку (результирующий объект BitmapData).
Главная проблема — организовать всё так, чтобы флэш-плагин не умер при перерисовке большого количества пикселей.

О варианте с клипами можно сразу забыть (сделать каждый пиксель клипом и задать ему движение). В этом случае флэш плеер может упасть в обморок уже при первой попытке отобразить строки. Это не удивительно: каждый символ — это 20-40 пикселей, а каждый клип — это множество свойств, которые плеер должен обновлять, перерисовывая кадр.

Напрашивается вывод: нужно просчитывать положение пикселей в каких-то невизуальных объектах, а потом выводить общую картину в объект BitmapData. В моем примере я создал несколько классов для управления всей этой системой.
  • Класс Pixel. Объект этого класса заведует положением и цветом одной точки.
  • Класс PixelCharacter. Объект этого класса управляет списком объектов Pixel, из которых состоит один символ шрифта.
  • Класс PixelString. Объект этого класса управляет списком объектов PixelСharacter, из которых состоит строка.
  • Класс PixelFont управляет списком объектов класса PixelСharacter, по одному для каждого из символов шрифта. При необходимости собрать строку символы PixelCharacter копируются в объект класса PixelString.
Все эти классы являются моделью. Объекты этих классов не имеют собственного визуального представления. Когда необходимо сдвинуть пиксели — объекту класса PixelString дается команда с параметрами сдвига, и этот объект раздает необходимые указания списку символов PixelCharacter, а те в свою очередь управляют пикселями, из которых состоят. После того, как выполняется смещение пикселей, объекту PixelString передается ссылка на экземпляр BitmapData, в который нужно вывести получившиеся точки. (Заметим, здесь есть простор для оптимизации: можно отрисовывать каждый пиксель уже при установке его нового положения.)

В моем примере все смещения пикселей задаются относительно их "нормального" положения. То есть, относительно их положения в символе шрифта. Направление сдвига по координатам выбирается либо случайно, либо с учетом угла разлета. Всё это делается в классах модели — Pixel, PixelCharacter и PixelString. Всё использование этих классов сводится к обращениям "сдвинь пиксели в такую-то сторону" и "нарисуй то, что получилось, вот сюда".

Еще одна тонкость — при перерисовке общей картины совсем не обязательно сразу стирать предыдущую. В моем примере эффект распыления достигается за счет того, что на экране одновременно присутствуют изображения нескольких шагов движения пикселей. Я задал кольцевой стэк небольшой глубины: каждая новая картинка кладется наверх стэка, если длина стэка после этого превышает допустимую, самая "старая" картинка стирается. Благодаря этому приему мы видим "трассу" пикселей.


в начало

3. Тормозит. :( Как с этим бороться?

Первый совет: рисовать меньше пикселей. :) При перерисовке в одном кадре 300-400 пикселей флэш плеер обычно ведет себя терпимо. Но если вы хотите создать более масштабную анимацию, придется организовать раздельную отрисовку шагов движения. То есть, нужно ограничить количество итераций за время одного кадра и продолжить прерванную перерисовку в следующих кадрах. Для этого может понадобиться просчитать положения пикселей предварительно, на несколько шагов вперед или для всего движения целиком. В любом случае, здесь вряд ли удастся добиться идеального результата — нужно искать пути изменения самой задачи.

В этом свете подобные пиксельные эффекты над картинками представляют особую сложность. Сделать не сложно — но быстро работать, увы, не будет.

Второй совет: preprocess, preprocess, preprocess © авторы игры N. Просчитывайте всё, что можно просчитать, до того как анимация начинает проигрываться. Лучше занять мегабайт-другой оперативной памяти, чем заставлять посетителя слушать разгоняющийся кулер на процессоре.

И помните: самая гениальная анимация не будет оценена по достоинству, если из-за неё в броузере не нажимаются кнопки и музыка в мп3 плеере заикается.
в начало
назад к списку уроков и рецептов