Статьи

Совет: добавьте эффект Blurry Trail к вашим пулям

В этом кратком совете вы узнаете, как использовать метод copyPixels() BitmapData для создания очень быстрого эффекта размытого следа для пуль в играх «стреляй».


Давайте посмотрим на конечный результат, к которому мы будем стремиться:

Используйте клавиши со стрелками или WASD, чтобы переместить корабль, и нажмите пробел, чтобы стрелять в направлении курсора мыши.


Мы быстро (очень быстро) рассмотрим основную идею, используемую в блиттинге, прежде чем двигаться дальше, поскольку мы будем использовать ее в этом кратком совете.

Копирование пикселей на экране является основой блиттинга. В AS3 это делается путем копирования прямоугольной области пикселей BitmapData в другую BitmapData с использованием BitmapData.copyPixels() .

Копирование пикселей с изображения

Изображение выше иллюстрирует именно это. Мы копируем пиксели прямоугольной области из BitmapData и помещаем ее в другую.

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


В исходных файлах уже есть базовый код для игры в космический шутер, так как это не тема этого поста. Есть только корабль, который движется с WASD или клавишами со стрелками. Код очень прокомментирован и очень прост, поэтому у вас, вероятно, не возникнет проблем с его пониманием. Он использует встроенные изображения для изображений в вашей игре, но вы также можете использовать спрайты с очень легким поворотом к функции, которую мы создадим позже (мы обсудим это чуть позже).

Давайте Main.as к Main.as и создадим Bitmap которое будет содержать все Main.as и объекты, которые должны быть размыты. Добавьте это прежде всего в список детей.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private var _container:Bitmap;
private var _containerData:BitmapData;
 
private function init(e:Event = null):void
{
    removeEventListener(Event.ADDED_TO_STAGE, init);
     
    // Creating player ship and the vector that will contain the bullets
    _playerShip = new PlayerShip();
     
    _bullets = new Vector.<PlayerBullet>();
    //
     
    // Initializing the container
    _containerData = new BitmapData(550, 400, true, 0xFFFFFFFF);
    _container = new Bitmap(_containerData);
    //
     
    addChild(_container);
    addChild(_playerShip);
     
    // Listener for the game loop
    addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

Пока что все было очень просто. Мы только создали контейнер и добавили его в список отображения.


На этом этапе нам нужно нарисовать маркеры в контейнере каждый кадр. Мы сделаем это в функции onEnterFrame() класса Main .

01
02
03
04
05
06
07
08
09
10
11
12
13
private function onEnterFrame(e:Event):void
{
    _playerShip.update();
     
    // Updating every bullet
    for (var i:int = 0; i < _bullets.length; i++)
    {
        _bullets[i].update();
         
        _containerData.copyPixels(Bitmap(_bullets[i].getChildAt(0)).bitmapData, Bitmap(_bullets[i].getChildAt(0)).bitmapData.rect, new Point(_bullets[i].x, _bullets[i].y));
    }
    //
}

Единственная важная строка – это строка 10. В этой строке мы рисуем пиксели каждого маркера (путем доступа к BitmapData дочернего элемента BitmapData , который является BitmapData содержащим пиксели встроенного изображения) в их положение. Если вы не используете встроенные изображения в своей игре, вместо этого вы можете использовать BitmapData.draw() . Этот метод немного медленнее, но он будет работать так же.

Мы пропускаем весь прямоугольник BitmapData пули, потому что хотим нарисовать все это. Вы можете поиграть с этим прямоугольником и позицией для рисования, чтобы получить очень забавные результаты (например, позицию, основанную на периодической функции, такой как Math.sin() чтобы создать интересный эффект следа, даже если пуля идет только по прямой линия, или только рисование “огня” пули ракеты, минуя меньший прямоугольник, чтобы создать след только с выстрелом).

Когда вы скомпилируете и запустите свою игру, вы получите что-то вроде этого после стрельбы несколькими пулями:

Трассы не исчезают

Однако это не то, что мы действительно хотим. Мы хотим добавить эффект размытого следа, что делать?


Это последний шаг. Все, что нам осталось сделать, это применить эффект размытия в BitmapData который содержит все изображения из маркеров. Для этого мы будем использовать ColorMatrixFilter .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
private var _colorMatrixFilter:ColorMatrixFilter;
 
private function init(e:Event = null):void
{
    removeEventListener(Event.ADDED_TO_STAGE, init);
     
    // Creating player ship and the vector that will contain the bullets
    _playerShip = new PlayerShip();
     
    _bullets = new Vector.<PlayerBullet>();
    //
     
    // Initializing the container
    _containerData = new BitmapData(550, 400, true, 0);
    _container = new Bitmap(_containerData);
    //
     
    // Initializing the matrix filter
    _colorMatrixFilter = new ColorMatrixFilter([ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0.99, 0 ]);
    //
     
    addChild(_container);
    addChild(_playerShip);
     
    // Listener for the game loop
    addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
 
private function onEnterFrame(e:Event):void
{
    _playerShip.update();
     
    // Updating every bullet
    for (var i:int = 0; i < _bullets.length; i++)
    {
        _bullets[i].update();
         
        _containerData.copyPixels(Bitmap(_bullets[i].getChildAt(0)).bitmapData, Bitmap(_bullets[i].getChildAt(0)).bitmapData.rect, new Point(_bullets[i].x, _bullets[i].y));
    }
    //
     
    // Adding the blur effect on the container
    _containerData.applyFilter(_containerData, _containerData.rect, new Point(0, 0), new BlurFilter(2, 2, 1));
    _containerData.applyFilter(_containerData, _containerData.rect, new Point(0, 0), _colorMatrixFilter);
    //
}

ColorMatrixFilter работает, управляя каждым пикселем в BitmapData соответствии со значениями в матричном фильтре. Посмотрите на функцию init() . ColorMatrixFilter мы создаем новый ColorMatrixFilter , передавая массив с кучей значений в нем. Эти значения создадут матрицу преобразования матричного фильтра, что позволит нам манипулировать пикселями в изображении.

Фильтр работает в основном так: каждый компонент результирующего цвета (красный, зеленый, синий и альфа) рассчитывается путем умножения исходных компонентов на соответствующие числа в соответствующей строке матрицы и суммирования их вместе с пятым значением ряда.

Например, если мы возьмем матричный фильтр, который мы создали в коде, в качестве нашего примера матричного фильтра, и мы применяем его к пикселю со значениями « red = 50, green = 10, blue = 200, alpha = 128 », в результате красный компонент пикселя будет иметь вид « red = (50 * 1) + (10 * 0) + (200 * 0) + (128 * 0) + 0 = 50 », поскольку первая строка нашей матрицы равна « 1 0 0 0 0 “. Альфа-компонент будет иметь вид « alpha = (50 * 0) + (10 * 0) + (200 * 0) + (128 * 0.99) + 0 = 126 », поскольку последняя строка нашей матрицы равна « 0 0 0 0.99 0 “.

Вы видите, что происходит сейчас? Каждый кадр мы умножаем альфа каждого пикселя на 0,99, делая его немного более прозрачным, чтобы создать эффект следа. Если вы хотите узнать больше о ColorMatrixFilter , вы можете обратиться к документации .

Эффект размытия позаботится о применении простого BlurFilter в BitmapData .

Скомпилируйте игру сейчас и вы получите желаемый эффект!


Вы только что узнали, как применить ColorMatrixFilter для создания эффекта размытого следа, используя очень быстрый метод BitmapData.copyPixels() ! Благодаря этому вы можете добавить эффект размытия к каждому объекту, который вам нужен, и не беспокоиться о замедлении Flash Player, потому что вы добавляете слишком много детей с фильтрами размытия на сцене. С помощью этого принципа можно построить много интересных вещей; Вы просто должны быть творческими.

Спасибо за чтение! Если у вас есть какие-либо вопросы, пожалуйста, прокомментируйте!