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