В этом кратком совете мы собираемся использовать ColorMatrixFilter и BlurFilter для создания эффекта Motion Trail.
Мы нашли этого замечательного автора благодаря FlashGameLicense.com , месту, где можно покупать и продавать флэш-игры.
Окончательный результат предварительного просмотра
Давайте посмотрим на конечный результат, к которому мы будем стремиться:
Шаг 1. Создайте проект и настройте его
Создайте новый проект в FlashDevelop (или любом другом редакторе), установите размеры SWF 600×400 и фон черный (# 000000).
Далее, чтобы настроить сцену, у нас будет два Sprites , один для основного экрана, к которому мы добавим все экранные объекты, а другой для эффекта «След движения», который использует основной экран в качестве эталона.
|
1
2
|
private var _mainDisplay:Sprite = new Sprite();
private var _mtDisplay:Sprite = new Sprite();
|
И добавьте Sprites на Stage .
|
1
2
3
4
5
6
|
//
// Set up Displays
// We have to add our two displays to the Stage
addChild(_mtDisplay);
addChild(_mainDisplay);
|
Теперь мы собираемся встроить наше изображение звезды для использования, или если вы хотите использовать свое собственное изображение.

|
1
2
|
[Embed(source = ‘../../images/star.png’)]
var star:Class;
|
Последнее, что мы хотим сделать для настройки, это создать функцию loop . Это будет обновляться каждый кадр, для таких вещей, как позиционирование и обновление трассы движения. Поэтому создайте другую функцию и прослушиватель событий, чтобы вызывать ее каждый кадр.
Ваш класс 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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package rtmTrail
{
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
//
// Load Images
[Embed(source = ‘../../images/star.png’)]
var star:Class;
//
// Set up Displays
// We have to add our two displays to the stage
addChild(_mtDisplay);
addChild(_mainDisplay);
// Add a new Event Listener for our loop function whenever we enter
// the frame to move the sprites and update our MotionTrail Effect
addEventListener(Event.ENTER_FRAME, loop);
}
private function loop(e:Event):void
{
}
private var _mainDisplay:Sprite = new Sprite();
private var _mtDisplay:Sprite = new Sprite();
}
}
|
Шаг 2: Спрайты и TextField
Чтобы протестировать Motion Trail, мы собираемся создать десять Sprites из изображения звезды и расположить их в случайных местах. Кроме того, мы собираемся создать Point которая сообщает нам скорость и направление их движения. Первое, что нужно сделать, это создать два Arrays для хранения этой информации; один для Sprite а другой для Point .
|
1
2
3
|
private var _sprites:Array = new Array();
private var _spritesDir:Array = new Array();
private var _txt:TextField = new TextField();
|
Добавьте это к функции init чтобы случайным образом создать и разместить десять звезд.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
// Draw some stars
var spr:Sprite;
var bmp:Bitmap;
for (var i:int = 0; i < 10; i++)
{
spr = new Sprite();
bmp = new star();
spr.addChild(bmp);
bmp.smoothing = true;
spr.x = Math.random() * 240 + 80;
spr.y = Math.random() * 240 + 80;
// We are going to add the new sprite into the _sprites Array and a
// Point that tells us where to move the sprite in the _spritesDir Array.
_sprites.push(spr);
_spritesDir.push(new Point(Math.random() * 6, Math.random() * 6));
// Last thing to do is add it to our main Display
_mainDisplay.addChild(spr);
}
|
Теперь, чтобы создать TextField добавьте это.
|
1
2
3
4
5
6
7
|
// Add a Text Field Too
_txt.defaultTextFormat = new TextFormat(«arial», 18, 0xFF00FF);
_txt.text = «Real Time Motion Trail»
_txt.x = 20;
_txt.y = 10;
_txt.width = 200;
_mainDisplay.addChild(_txt);
|
Шаг 3: Управление движением спрайта
Теперь мы должны перейти к нашей функции loop для управления движением Sprite . Довольно просто, используйте цикл for чтобы пройти через каждый Sprite у нас есть, и если он достигает края, инвертирует x или y Point чтобы он шел в другом направлении. Нам также придется перемещать спрайт в цикле по значениям в Point и, чтобы сделать его более интересным, медленно вращать его.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
private function loop(e:Event):void
{
// Update the Sprite Shapes
for (var i:int = 0; i < _sprites.length; i++)
{
// Check to see if the shape is at or out of the
// outer bounds so we can change direction
if (_sprites[i].x <= 0 || _sprites[i].x >= 600) _spritesDir[i].x = -_spritesDir[i].x;
if (_sprites[i].y <= 0 || _sprites[i].y >= 400) _spritesDir[i].y = -_spritesDir[i].y;
// Move the Sprite Shape
_sprites[i].x += _spritesDir[i].x;
_sprites[i].y += _spritesDir[i].y;
// Rotate Sprite Shape
_sprites[i].rotation += 2;
}
}
|
Чтобы переместить TextField через верхнюю часть влево, мы просто должны вычитать из свойства x каждый кадр, а если он выходит за пределы экрана, вернуть его обратно в правую часть экрана.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
private function loop(e:Event):void
{
// Update the Sprite Shapes
for (var i:int = 0; i < _sprites.length; i++)
{
// Check to see if the shape is at or out of the
// outer bounds so we can change direction
if (_sprites[i].x <= 0 || _sprites[i].x >= 600) _spritesDir[i].x = -_spritesDir[i].x;
if (_sprites[i].y <= 0 || _sprites[i].y >= 400) _spritesDir[i].y = -_spritesDir[i].y;
// Move the Sprite Shape
_sprites[i].x += _spritesDir[i].x;
_sprites[i].y += _spritesDir[i].y;
// Rotate Sprite Shape
_sprites[i].rotation += 2;
}
// Move Text
_txt.x -= 4
if (_txt.x < -200) _txt.x = 600;
}
|
Протестировав его, вы должны были увидеть что-то подобное (со звездами и текстом, конечно, движущимися по экрану).

Шаг 4. Создайте класс MotionTrail
Теперь пришло время сделать наш класс MotionTrail . Этот класс собирается использовать DisplayObject который рисуется на собственном дисплее ( Sprite ) и использует пару фильтров, затемненных и размытых.
Поэтому создайте свой новый класс MotionTrail.as и позвольте ему расширить класс Sprite .
Для небольшой предварительной настройки для следующих шагов мы собираемся создать несколько переменных: сначала _display для хранения ссылки на главный дисплей, BitmapData для рисования, Rectangle размер сцены и Point в верхний левый угол для фильтров. Последнее — это Array для 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
|
package rtmTrail
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.geom.Point;
import flash.geom.Rectangle;
public class MotionTrail extends Sprite
{
public function MotionTrail(display:DisplayObject)
{
// Reference to the display used for the motion trail
_display = display;
// Make a BitmapData Object to draw to
// If you want to use this for your own project and the dimensions isn’t 600×400
// then you would have to change it here and the rectangle below
_bitmapData = new BitmapData(600, 400, true, 0x000000);
// Some Stuff that the filters need inputed for it to work
_rect = new Rectangle(0, 0, 600, 400);
_pnt = new Point(0, 0);
_cMatrix = new Array();
// Add a little transparency so it doesn’t take attention away from the Main Display
alpha = 0.6;
addChild(new Bitmap(_bitmapData));
}
private var _display:DisplayObject;
private var _bitmapData:BitmapData;
private var _rect:Rectangle;
private var _pnt:Point;
private var _cMatrix:Array;
}
}
|
Поскольку мы создали этот класс, нам нужно очень быстро вернуться к переменной _mtDisplay и изменить ее с класса Sprite класс MotionTrail вместе с _mainDisplay переменной _mainDisplay .
|
1
2
|
private var _mainDisplay:Sprite = new Sprite();
private var _mtDisplay:MotionTrail = new MotionTrail(_mainDisplay);
|
Шаг 5: Массив ColorMatrixFilter
Чтобы создать нашу Matrix для ColorMatrixFilter , основная идея состоит в том, чтобы ColorMatrixFilter цвета, поэтому мы постепенно уменьшаем все значения до нуля. Добавьте это к constructor .
|
1
2
3
4
5
|
// Create Matrix for ColorMatrixFilter
_cMatrix = _cMatrix.concat([0.92, 0, 0, 0, 0]) // Red
_cMatrix = _cMatrix.concat([0, 0.92, 0, 0, 0]) // Green
_cMatrix = _cMatrix.concat([0, 0, 0.92, 0, 0]) // Blue
_cMatrix = _cMatrix.concat([0, 0, 0, 0.92, 0]) // Alpha
|
Это умножит каждое значение каждого пикселя на 0,92, и при этом каждый кадр будет становиться все меньше и меньше, пока не достигнет своего предела в 0. Таким образом, чем ближе значения к 1,0, тем больше времени требуется для достижения нуля, что означает более длинный след (и наоборот: чем ближе к 0,0, тем короче след).
Шаг 6: ColorMatrixFilter и BlurFilter
Теперь мы создаем ColorMatrixFilter и BlurFilter .
ColorMatrixFilter будет использовать Array мы только что создали, и мы собираемся создать два BlurFilters . Я обнаружил, что использование двух BlurFilters дает хороший импульсный эффект, и он не размывается слишком медленно или слишком быстро, но если у вас есть такой, то это тоже хорошо.
Сначала добавьте переменные для фильтров.
|
1
2
3
|
private var _cFilter:ColorMatrixFilter;
private var _bFilter:BlurFilter;
private var _bFilter2:BlurFilter;
|
Создайте фильтры в конструкторе
|
1
2
3
|
_cFilter = new ColorMatrixFilter(_cMatrix);
_bFilter = new BlurFilter(2, 2, 1);
_bFilter2 = new BlurFilter(8, 8, 1);
|
Шаг 7: Обновление MotionTrails
Теперь пришло время создать функцию для обновления наших Motion Trails. Сделайте функцию с именем update в классе MotionTrail . Чтобы создать трейл, мы должны нарисовать основной дисплей для BitmapData каждый кадр, который создает эффект трейла.
|
1
2
3
4
5
|
public function update():void
{
// Draw Display onto BitmapData
_bitmapData.draw(_display);
}
|
Теперь у вас должен быть след, если вы его запустите, но, конечно, следы движения исчезают, и мы уберем его с помощью фильтров, которые мы сделали на последнем шаге.

Шаг 8: применение фильтров
Теперь мы можем применить фильтры к BitmapData . Мы используем одни и те же BitmapData для источника, переменные _rect и _pnt для sourceRect и destPoint соответственно, а последний — это фильтр, который мы хотим применить.
Поскольку у нас есть несколько фильтров, мы не хотим применять их все в каждом кадре, потому что это слишком сильно замедляет работу. Вместо этого мы собираемся переключить ColorMatrixFilter и BlurFilter для работы в разных кадрах и переключать BlurFilters таким же образом.
Чтобы переключить их, у нас будет переменная для отслеживания кадра и использование оператора модуля для проверки.
|
1
|
private var _count:Number = 0;
|
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public function update():void
{
// Draw Display onto BitmapData
_bitmapData.draw(_display);
// Apply Effects to BitmapData
if (_count % 2 == 0)
_bitmapData.applyFilter(_bitmapData, _rect, _pnt, _cFilter);
else
if (_count % 4 == 1)
_bitmapData.applyFilter(_bitmapData, _rect, _pnt, _bFilter);
else
_bitmapData.applyFilter(_bitmapData, _rect, _pnt, _bFilter2);
// Increase Count
_count++;
}
|
Теперь, когда функция update завершена, мы добавляем ее в нашу функцию loop .
|
1
2
|
// Update Motion Blur
_mtDisplay.update();
|
Заключение Тестирование и расширение
Потрясающие! Мы закончили с этим Quick Tip, и вы можете проверить его.
Вы должны были получить тот же результат, что и образец swf, и теперь вы можете попробовать его расширить. Существует множество различных эффектов, большинство из которых, если вы понимаете ColorMatrixFilter .
Например, вы можете изменить цвет следа на красный, выполнив это:
|
1
2
3
4
5
|
// Offset Red Value by 30 each time
_cMatrix = _cMatrix.concat([0.92, 0, 0, 0, 30]) // Red
_cMatrix = _cMatrix.concat([0, 0.92, 0, 0, 0]) // Green
_cMatrix = _cMatrix.concat([0, 0, 0.92, 0, 0]) // Blue
_cMatrix = _cMatrix.concat([0, 0, 0, 0.92, 0]) // Alpha
|

Или вы можете также поменять цвета, чтобы все трассы были синими:
|
1
2
3
4
5
|
// Only Blue trails
_cMatrix = _cMatrix.concat([0, 0, 0, 0, 0]) // Red
_cMatrix = _cMatrix.concat([0, 0, 0, 0, 0]) // Green
_cMatrix = _cMatrix.concat([0.92, 0.92, 0.92, 0, 0]) // Blue
_cMatrix = _cMatrix.concat([0, 0, 0, 0.92, 0]) // Alpha
|

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