Статьи

Быстрый совет: ускорение движения в реальном времени

В этом кратком совете мы собираемся использовать ColorMatrixFilter и BlurFilter для создания эффекта Motion Trail.

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


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


Создайте новый проект в 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();
 
    }
}

Чтобы протестировать 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);

Теперь мы должны перейти к нашей функции 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;
}

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


Теперь пришло время сделать наш класс 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);

Чтобы создать нашу 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, тем короче след).


Теперь мы создаем 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);

Теперь пришло время создать функцию для обновления наших Motion Trails. Сделайте функцию с именем update в классе MotionTrail . Чтобы создать трейл, мы должны нарисовать основной дисплей для BitmapData каждый кадр, который создает эффект трейла.

1
2
3
4
5
public function update():void
{
    // Draw Display onto BitmapData
    _bitmapData.draw(_display);
}

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


Теперь мы можем применить фильтры к 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

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