В этом кратком совете вы узнаете, как использовать метод copyPixels()
BitmapData для создания очень быстрого эффекта размытого следа для пуль в играх «стреляй».
Окончательный результат предварительного просмотра
Давайте посмотрим на конечный результат, к которому мы будем стремиться:
Используйте клавиши со стрелками или WASD, чтобы переместить корабль, и нажмите пробел, чтобы стрелять в направлении курсора мыши.
Шаг 1: Введение и основы блиттинга
Мы быстро (очень быстро) рассмотрим основную идею, используемую в блиттинге, прежде чем двигаться дальше, поскольку мы будем использовать ее в этом кратком совете.
Копирование пикселей на экране является основой блиттинга. В AS3 это делается путем копирования прямоугольной области пикселей BitmapData
в другую BitmapData
с использованием BitmapData.copyPixels()
.
Изображение выше иллюстрирует именно это. Мы копируем пиксели прямоугольной области из BitmapData
и помещаем ее в другую.
Идея, которую мы рассмотрим в этом кратком совете, состоит в том, чтобы скопировать все, что требует эффекта размытия, в контейнер и применить эффекты постблитинга, чтобы создать нужный эффект.
Шаг 2: Растровый контейнер
В исходных файлах уже есть базовый код для игры в космический шутер, так как это не тема этого поста. Есть только корабль, который движется с 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);
}
|
Пока что все было очень просто. Мы только создали контейнер и добавили его в список отображения.
Шаг 3: Рисование пуль в контейнере
На этом этапе нам нужно нарисовать маркеры в контейнере каждый кадр. Мы сделаем это в функции 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()
чтобы создать интересный эффект следа, даже если пуля идет только по прямой линия, или только рисование «огня» пули ракеты, минуя меньший прямоугольник, чтобы создать след только с выстрелом).
Когда вы скомпилируете и запустите свою игру, вы получите что-то вроде этого после стрельбы несколькими пулями:
Однако это не то, что мы действительно хотим. Мы хотим добавить эффект размытого следа, что делать?
Шаг 4: Добавление эффекта размытия
Это последний шаг. Все, что нам осталось сделать, это применить эффект размытия в 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
.
Скомпилируйте игру сейчас и вы получите желаемый эффект!
Шаг 5: И это все
Вы только что узнали, как применить ColorMatrixFilter
для создания эффекта размытого следа, используя очень быстрый метод BitmapData.copyPixels()
! Благодаря этому вы можете добавить эффект размытия к каждому объекту, который вам нужен, и не беспокоиться о замедлении Flash Player, потому что вы добавляете слишком много детей с фильтрами размытия на сцене. С помощью этого принципа можно построить много интересных вещей; Вы просто должны быть творческими.
Спасибо за чтение! Если у вас есть какие-либо вопросы, пожалуйста, прокомментируйте!