Статьи

Мышление в командах: часть 2 из 2

В этом уроке мы дополнительно расширим структуру команд из первой части. Мы создадим инфраструктуру управления сценой с легко понятным и поддерживаемым кодом.


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


Один разумный способ разбить полное приложение Flash на более мелкие части — это управлять им как отдельными сценами. Flash IDE позволяет выполнять управление сценой без написания кода, но мы собираемся подойти к этому совершенно по-другому. Мы создадим нашу собственную структуру управления сценой.

В нашей среде управления сценами мы рассматриваем сцены как наименьшие строительные блоки для полного приложения Flash. Каждая сцена состоит из вступительной команды и выходной команды. Команда intro инициализирует все, что вам нужно для сцены, например, добавление логотипа в список отображения вашего спрайта контейнера. Команда outro делает прямо противоположное, например, удаляет логотип из спрайта контейнера. Вы можете рассматривать переход от одной сцены к другой как команду outro первой сцены, за которой следует команда intro второй. Таким образом, мы можем соединять сцены и очень легко управлять их переходами.

Посмотрите на эту фигуру. Одна сцена похожа на кусок головоломки; левый конец представляет команду intro, а правый конец представляет команду outro.

Выполнение перехода от сцены A к сцене B аналогично соединению двух частей вместе. Сначала выполняется команда outro сцены A, затем выполняется команда intro сцены B, затем переход сцены завершается.

Это в основном та же самая концепция, чтобы выполнить переход от сцены A к сцене C. Мы просто должны собрать кусочки головоломки A и C вместе, а не A и B.


Прежде чем мы начнем создавать среду управления сценой, давайте сначала создадим еще несколько командных классов, которые позже будут использованы в этом руководстве. Вы можете просто сосредоточиться на переопределенных методах execute () следующих командных классов, которые являются наиболее важной частью этих классов.


Без сомнения, GreenSock Tweening Platform является одной из лучших фреймворков с открытым исходным кодом. Переходы между сценами обычно включают в себя множество анимаций, и платформа GreenSock Tweening всегда была моим первым выбором, когда речь шла о создании анимаций. Мы собираемся инкапсулировать этот каркас в классы команд, чтобы интегрировать его с нашим каркасом команд. Загрузите библиотеку TweenMax и установите ее.

Мы будем использовать методы to () и from () из класса TweenMax. Класс TweenMax обеспечивает способ обработки завершения анимации, вызывая функцию, на которую ссылается необязательное свойство «onComplete» в параметре «vars». Мы назначим метод complete () команды этому свойству, поэтому метод complete () вызывается после завершения анимации. Ниже приведен код для команд, инкапсулирующих эти два метода. Создайте новый каталог с именем «greensock» внутри каталога «команд», который вы создали в первой части этого учебного пособия, и сохраните эти классы как TweenMaxTo.as и TweenMaxFrom.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
package commands.greensock {
    import com.greensock.TweenMax;
    import commands.Command;
     
    //this command encapsulates the TweenMax.to() method
    public class TweenMaxTo extends Command {
         
        public var target:Object;
        public var duration:Number;
        public var vars:Object;
         
        public function TweenMaxTo(target:Object, duration:Number, vars:Object) {
            this.target = target;
            this.duration = duration;
            this.vars = vars;
        }
         
        override protected function execute():void {
            //tell TweenMax to invoke the command’s complete() method when the tweening is done
            vars.onComplete = complete;
            TweenMax.to(target, duration, vars);
        }
    }
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package commands.greensock {
    import com.greensock.TweenMax;
    import commands.Command;
     
    //this command encapsulates the TweenMax.from() method
    public class TweenMaxFrom extends Command {
         
        public var target:Object;
        public var duration:Number;
        public var vars:Object;
         
        public function TweenMaxFrom(target:Object, duration:Number, vars:Object) {
            this.target = target;
            this.duration = duration;
            this.vars = vars;
        }
         
        override protected function execute():void {
            //tell TweenMax to invoke the command’s complete() method when the tweening is done
            vars.onComplete = complete;
            TweenMax.from(target, duration, vars);
        }
    }
}

(Обязательно перечитайте мое введение в команды, если вам нужно обновить память.)

TweenMaxTo переместит целевой объект от его текущей позиции (или размытия, или альфы, или …) до новой позиции (и т. Д.), Которую вы укажете с помощью объекта vars. TweenMaxFrom делает противоположное.

Если вы достаточно знакомы с платформой GreenSock Tweening, вы также можете инкапсулировать классы TweenLite и TweenNano в соответствии со своими потребностями.


Как упоминалось ранее, вступление и выход из сцены могут, вероятно, включать добавление экранных объектов в контейнер экранных объектов и удаление объектов из контейнера. Итак, давайте инкапсулируем методы addChild () и removeChild () в команды.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
package commands.display {
    import commands.Command;
    import flash.display.DisplayObject;
    import flash.display.DisplayObjectContainer;
     
    //This command encapsulates the addChild() method
    public class AddChild extends Command {
         
        public var container:DisplayObjectContainer;
        public var displayObject:DisplayObject
         
        public function AddChild(container:DisplayObjectContainer, displayObject:DisplayObject) {
            this.container = container;
            this.displayObject = displayObject;
        }
         
        override protected function execute():void {
            container.addChild(displayObject);
            complete();
        }
    }
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
package commands.display {
    import commands.Command;
    import flash.display.DisplayObject;
    import flash.display.DisplayObjectContainer;
     
    //This command encapsulates the removeChild() method
    public class RemoveChild extends Command {
         
        public var container:DisplayObjectContainer;
        public var displayObject:DisplayObject
         
        public function RemoveChild(container:DisplayObjectContainer, displayObject:DisplayObject) {
            this.container = container;
            this.displayObject = displayObject;
        }
         
        override protected function execute():void {
            container.removeChild(displayObject);
            complete();
        }
    }
}

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package commands.events {
    import commands.Command;
    import flash.events.IEventDispatcher;
     
    //this command encapsulates the addEventListener() method
    public class AddEventListener extends Command {
         
        public var dispatcher:IEventDispatcher;
        public var type:String;
        public var listener:Function;
         
        public function AddEventListener(dispatcher:IEventDispatcher, type:String, listener:Function) {
            this.dispatcher = dispatcher;
            this.type = type;
            this.listener = listener;
        }
         
        override protected function execute():void {
            dispatcher.addEventListener(type, listener);
            complete();
        }
    }
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package commands.events {
    import commands.Command;
    import flash.events.IEventDispatcher;
     
    //this command encapsulates the removeEventListener() method
    public class RemoveEventListener extends Command {
         
        public var dispatcher:IEventDispatcher;
        public var type:String;
        public var listener:Function;
         
        public function RemoveEventListener(dispatcher:IEventDispatcher, type:String, listener:Function) {
            this.dispatcher = dispatcher;
            this.type = type;
            this.listener = listener;
        }
         
        override protected function execute():void {
            dispatcher.removeEventListener(type, listener);
            complete();
        }
    }
}

Наконец, нам понадобятся некоторые служебные команды, чтобы упростить процесс. Команда SetProperties устанавливает свойства объекта из значений свойств другого объекта:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
package commands.utils {
    import commands.Command;
     
    //this command sets an object’s properties in a quick and convenient way
    public class SetProperties extends Command {
         
        public var target:Object;
        public var properties:Object;
         
        public function SetProperties(target:Object, properties:Object) {
            this.target = target;
            this.properties = properties;
        }
         
        override protected function execute():void {
            for (var key:String in properties) {
                target[key] = properties[key];
            }
            complete();
        }
    }
}

Мы можем использовать это так:

1
var setProperties:SetProperties = new SetProperties(target, {x:100, y:230});

… и он установит свойства x и y целевого объекта в указанные значения.

Команда Dummy просто ничего не делает и завершает выполнение команды. Цель этой команды состоит в том, чтобы служить в качестве «заполнителя» и станет ясно позже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
package commands.utils {
    import commands.Command;
     
    //this command simply does nothing and completes itself upon execution
    public class Dummy extends Command {
         
        public function Dummy() {
             
        }
         
        override protected function execute():void {
            complete();
        }
    }
}

Команда Wait ожидает указанное время задержки и затем завершает выполнение команды, ничего не делая:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package commands.utils {
    import commands.Command;
     
    public class Wait extends Command {
         
        public function Wait(delay:Number = 0) {
            super(delay);
        }
         
        override protected function execute():void {
            complete();
        }
    }
}

Вы можете задаться вопросом, зачем нам нужна команда, которая просто занимает время, если у нас уже есть параметр конструктора «delay» в базовом классе Command. Иногда нам хотелось бы, чтобы конструкторы имели только те параметры, которые действительно имеют какое-то отношение к специфическим функциям команды, и включение времени «задержки», поскольку один из них является своего рода нарушением «однородности» с точки зрения назначения параметров. Поэтому вместо написания кода ниже:

1
2
3
4
new SerialCommand(0,
    new SomeFancyCommand(delay1, fancyParam11, fancyParam12, fancyParam31),
    new SomeFancyCommand(delay2, fancyParam21, fancyParam22, fancyParam23)
);

Мы могли бы написать что-то вроде этого:

1
2
3
4
5
6
new SerialCommand(0,
    new Wait(delay1),
    new SomeFancyCommand(fancyParam11, fancyParam12, fancyParam31),
    new Wait(delay2),
    new SomeFancyCommand(fancyParam21, fancyParam22, fancyParam23)
);

Параметры «delay» больше не нужны из-за конструкторов SomeFancyCommand. Теперь они были перемещены в команды ожидания, чтобы сделать вещи чище.


Вот наш класс Scene, представляющий одну «часть головоломки». То, что делает каждый метод, объясняется в комментариях. Этот класс в значительной степени является «скелетным» классом, поскольку каждый метод либо создает фиктивную команду, либо ничего не делает. Чтобы сделать вещи более сочными, эти методы должны быть переопределены. Создайте новый каталог «сцены» в исходной папке вашего проекта для хранения этих новых классов:

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
package scenes {
    import commands.Command;
    import commands.utils.Dummy;
     
    //this class represents a scene for a complete Flash application
    public class Scene {
         
        //a reference to the scene manager owning this scene
        internal var _sceneManager:SceneManager;
        protected final function get sceneManager():SceneManager { return _sceneManager;
         
        //creates the intro command of this scene
        public function createIntroCommand():Command {
            return new Dummy();
        }
         
        //creates the outro command of this scene
        public function createOutroCommand():Command {
            return new Dummy();
        }
         
        //handle scene-related stuff here when the scene is set
        public function onSceneSet():void {
             
        }
    }
}

А вот класс SceneManager, который обрабатывает переходы сцен, подробности также объясняются в комментариях. Обратите внимание, что я добавил «переменную-пустышку», чтобы защитить переходы от несвоевременного вызова метода setScene ().

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package scenes {
    import commands.Command;
    import flash.events.Event;
     
    //this class handles scene transitions
    public class SceneManager {
         
        //a reference to the current scene
        private var _currentScene:Scene;
         
        //a reference to the target scene of a transition
        private var _targetScene:Scene;
         
        //dummy-proof variable
        private var _isInTransition:Boolean = false;
         
        public function SceneManager() {
             
        }
         
        public function setScene(scene:Scene):void {
            //if a transition is not finished, ignore the method invocation
            if (_isInTransition) return;
             
            _targetScene = scene;
             
            //turn on the dummy-proof variable
            _isInTransition = true;
             
            //check if a scene is already assigned to the scene manager
            if (_currentScene) {
                 
                //if yes, start the outro of the current scene first
                var outroCommand:Command = _currentScene.createOutroCommand();
                 
                //and listen for the complete event of the outro command
                outroCommand.addEventListener(Event.COMPLETE, onCurrentOutroComplete);
                outroCommand.start();
                 
            } else {
                //if not, start the intro of the target scene
                gotoTargetScene();
            }
        }
         
        //invoked when the outro command of the current scene is complete
        private function onCurrentOutroComplete(e:Event):void {
            Command(e.target).removeEventListener(Event.COMPLETE, onCurrentOutroComplete);
            gotoTargetScene();
        }
         
        private function gotoTargetScene():void {
            //set the scene manager reference of the target scene to this
            _targetScene._sceneManager = this;
             
            var introCommand:Command = _targetScene.createIntroCommand();
             
            //listen for the complete event of the intro command of the target scene
            introCommand.addEventListener(Event.COMPLETE, onTargetIntroComplete);
            introCommand.start();
        }
         
        //invoked when the intro command of the target scene is complete
        private function onTargetIntroComplete(e:Event):void {
            Command(e.target).removeEventListener(Event.COMPLETE, onTargetIntroComplete);
             
            //remove the scene manager reference of the previous scene
            if (_currentScene) _currentScene._sceneManager = null;
             
            //set the target scene as the current scene
            _currentScene = _targetScene;
             
            //turn off the dummy-proof variable
            _isInTransition = false;
             
            //and invoke the onSceneSet() method
            _currentScene.onSceneSet();
        }
    }
}

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


Откройте Flash IDE и создайте новый документ Flash. Назовите его «SceneTransitions» и создайте класс документа с тем же именем. Кроме того, вы можете разместить фон на сцене, если хотите.


Создайте 4 символа с текстом и назовите их в соответствии со следующим изображением. В этом примере экспортируйте каждый символ для ActionScript с именем класса, совпадающим с именем его символа.


Создайте символы и назовите их, как показано на следующем рисунке. Кроме того, разместите их экземпляры и назовите их, как показано Выделите все экземпляры и преобразуйте их как группу в другой символ с именем «Scene1Sprite». Затем вы можете удалить Scene1Sprite со сцены (но не из библиотеки).


Сделайте точно так же, как в предыдущем шаге, но на этот раз выберите все экземпляры и преобразуйте их в символ с именем «Scene2Sprite».


Класс документа удивительно прост. Просто создайте менеджер сцены и скажите менеджеру установить текущую сцену на вступительную сцену.

01
02
03
04
05
06
07
08
09
10
11
12
package {
    import flash.display.Sprite;
    import scenes.SceneManager;
     
    public class SceneTransitions extends Sprite {
         
        public function SceneTransitions() {
            var sceneManager:SceneManager = new SceneManager();
            sceneManager.setScene(new IntroScene(this));
        }
    }
}

Начальная сцена, которую мы установили для менеджера сцены — это вступительная сцена. Как следует из названия, эта сцена является просто вступлением к нашей главной сцене (а не вступлением к части «загадки» нашей главной сцены). Команда вступления (созданная с помощью метода переопределения createIntroCommand ()) этой вступительной сцены перемещает экземпляры символов в центр сцены (с помощью команды SetProperties), добавляет их в контейнер, изменяет их масштаб от нуля до масштаба 100%, и размывает их до нуля альфа, один за другим. Это достигается путем объединения всех отдельных команд в одну последовательную команду (как вы должны помнить из первой части ).

Когда команда intro завершена, вызывается метод onSceneSet (), и в этот момент доступно свойство sceneManager, и его метод setScene () может быть вызван для переключения сцены. В методе onSceneSet () вызывается метод setScene () менеджера сцены, который изменяется на Scene1 (класс, который мы создадим на следующем шаге). Так как мы не переопределяли createOutroCommand (), команда outro сцены вступления является фиктивной командой, которая ничего не делает.

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package {
    import commands.Command;
    import commands.display.AddChild;
    import commands.display.RemoveChild;
    import commands.greensock.TweenMaxFrom;
    import commands.greensock.TweenMaxTo;
    import commands.scenes.SetScene;
    import commands.SerialCommand;
    import commands.utils.SetProperties;
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.filters.BlurFilter;
    import scenes.Scene;
     
    public class IntroScene extends Scene {
         
        //constant parameters
        private static const ZOOM_IN_TIME:Number = 0.2;
        private static const HOLD_TIME:Number = 0.3;
        private static const BLUR_OUT_TIME:Number = 0.2;
        private static const BLUR_AMOUNT:Number = 20;
         
        private var container:Sprite;
         
        public function IntroScene(container:Sprite) {
            this.container = container;
        }
         
        override public function createIntroCommand():Command {
            var blur:BlurFilter = new BlurFilter(BLUR_AMOUNT, BLUR_AMOUNT, 2);
             
            //symbol instances
            var text1:DisplayObject = new IntroText1();
            var text2:DisplayObject = new IntroText2();
            var text3:DisplayObject = new IntroText3();
            var text4:DisplayObject = new IntroText4();
             
            //this is the serial command that links things together
            var command:Command =
                new SerialCommand(0,
                     
                    //»THIS»
                    new SetProperties(text1, {x:320, y:200}),
                    new AddChild(container, text1),
                    new TweenMaxFrom(text1, ZOOM_IN_TIME, {scaleX:0, scaleY:0}),
                    new TweenMaxTo(text1, BLUR_OUT_TIME, {delay:HOLD_TIME, alpha:0, blurFilter:blur}),
                    new RemoveChild(container, text1),
                     
                    //»IS»
                    new SetProperties(text2, {x:320, y:200}),
                    new AddChild(container, text2),
                    new TweenMaxFrom(text2, ZOOM_IN_TIME, {scaleX:0, scaleY:0}),
                    new TweenMaxTo(text2, BLUR_OUT_TIME, {delay:HOLD_TIME, alpha:0, blurFilter:blur}),
                    new RemoveChild(container, text2),
                     
                    //»AN»
                    new SetProperties(text3, {x:320, y:200}),
                    new AddChild(container, text3),
                    new TweenMaxFrom(text3, ZOOM_IN_TIME, {scaleX:0, scaleY:0}),
                    new TweenMaxTo(text3, BLUR_OUT_TIME, {delay:HOLD_TIME, alpha:0, blurFilter:blur}),
                    new RemoveChild(container, text3),
                     
                    //»INTRO»
                    new SetProperties(text4, {x:320, y:200}),
                    new AddChild(container, text4),
                    new TweenMaxFrom(text4, ZOOM_IN_TIME, {scaleX:0, scaleY:0}),
                    new TweenMaxTo(text4, BLUR_OUT_TIME, {delay:HOLD_TIME, alpha:0, blurFilter:blur}),
                    new RemoveChild(container, text4),
                );
             
            return command;
        }
         
        override public function onSceneSet():void {
            //when the scene is set, directly go to scene 1
            sceneManager.setScene(new Scene1(container));
        }
    }
}

Вы можете настроить значение констант, чтобы изменить эффекты анимации.


Теперь давайте посмотрим на класс Scene1. Текстовые поля перемещаются в положение один за другим; кнопки «intro_btn» и «scene2_btn» регистрируются прослушивателями событий щелчка мыши после того, как они перемещаются в положение, что достигается путем объединения команд для анимации движения и добавления слушателей с помощью последовательной команды.

Также стоит упомянуть команду AddChild, которая добавляет Scene1Sprite в контейнер. Он объединяется последовательно после команды Wait, ожидающей один кадр. Поскольку класс TweenMax обновляет все экранные объекты в следующем кадре после вызова метода TweenMax.from (), иногда вы можете увидеть быстрый «взгляд» объектов на их последних местах перед началом анимации. Цель команды Wait в данном случае — дать TweenMax достаточно времени для перемещения объектов в их соответствующие начальные места.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package {
    import commands.Command;
    import commands.display.AddChild;
    import commands.display.RemoveChild;
    import commands.events.AddEventListener;
    import commands.events.RemoveEventListener;
    import commands.greensock.TweenMaxFrom;
    import commands.greensock.TweenMaxTo;
    import commands.ParallelCommand;
    import commands.SerialCommand;
    import commands.utils.SetProperties;
    import commands.utils.Wait;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.filters.BlurFilter;
    import scenes.Scene;
     
    public class Scene1 extends Scene {
         
        //constant parameters
        private static const IN_TIME:Number = 0.4;
        private static const OUT_TIME:Number = 0.2;
        private static const DELAY_TIME:Number = 0.2;
        private static const BLUR_AMOUNT:Number = 20;
         
        private var container:Sprite;
        private var ss:Scene1Sprite;
        private var blur:BlurFilter;
         
        public function Scene1(container:Sprite) {
            this.container = container;
            ss = new Scene1Sprite();
        }
         
        override public function createIntroCommand():Command {
            var command:Command =
                new ParallelCommand(0,
                     
                    //»THIS»
                    new TweenMaxFrom(ss.text1_mc, IN_TIME, {x:-400}),
                     
                    //»IS»
                    new TweenMaxFrom(ss.text2_mc, IN_TIME, {y:-250, delay:DELAY_TIME}),
                     
                    //»SCENE»
                    new TweenMaxFrom(ss.text3_mc, IN_TIME, {y:250, delay:DELAY_TIME * 2}),
                     
                    //»1″
                    new TweenMaxFrom(ss.text4_mc, IN_TIME, {x:400, delay:DELAY_TIME * 3}),
                     
                    //intro button
                    new SerialCommand(0,
                        new TweenMaxFrom(ss.intro_btn, IN_TIME, {y:250, delay:DELAY_TIME * 4}),
                        new AddEventListener(ss.intro_btn, MouseEvent.CLICK, replayIntro)
                    ),
                     
                    //scene 2 button
                    new SerialCommand(0,
                        new TweenMaxFrom(ss.scene2_btn, IN_TIME, {y:250, delay:DELAY_TIME * 5}),
                        new AddEventListener(ss.scene2_btn, MouseEvent.CLICK, gotoScene2)
                    ),
                     
                    //move the scene 1 sprite to the center of the container
                    new SetProperties(ss, {x:300, y:200}),
                     
                    //add the scene 1 sprite to the container
                    //wait for one frame to allow things to be moved into proper places
                    new SerialCommand(0,
                        new Wait(1 / container.stage.frameRate),
                        new AddChild(container, ss)
                    )
                );
             
            return command;
        }
         
        override public function createOutroCommand():Command {
            var blur:BlurFilter = new BlurFilter(BLUR_AMOUNT, BLUR_AMOUNT, 3);
             
            var command:Command =
                new ParallelCommand(0,
                     
                    //remove display objects
                    new SerialCommand(0,
                        //»THIS»
                        new TweenMaxTo(ss.text1_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
                         
                        //»IS»
                        new TweenMaxTo(ss.text2_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
                         
                        //»SCENE»
                        new TweenMaxTo(ss.text3_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
                         
                        //»1″
                        new TweenMaxTo(ss.text4_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
                         
                        //intro button
                        new TweenMaxTo(ss.intro_btn, OUT_TIME, {alpha:0, blurFilter:blur}),
                         
                        //scene 2 button
                        new TweenMaxTo(ss.scene2_btn, OUT_TIME, {alpha:0, blurFilter:blur}),
                         
                        //remove scene 1 sprite
                        new RemoveChild(container, ss)
                    ),
                     
                    //remove event listeners
                    new RemoveEventListener(ss.intro_btn, MouseEvent.CLICK, replayIntro),
                    new RemoveEventListener(ss.scene2_btn, MouseEvent.CLICK, gotoScene2)
                );
             
            return command;
        }
         
        private function replayIntro(e:Event):void{
            sceneManager.setScene(new IntroScene(container));
        }
         
        private function gotoScene2(e:Event):void{
            sceneManager.setScene(new Scene2(container));
        }
    }
}

Класс Scene2 очень похож на Scene1; хотя какой-то текст изменился:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package {
    import commands.Command;
    import commands.display.AddChild;
    import commands.display.RemoveChild;
    import commands.events.AddEventListener;
    import commands.events.RemoveEventListener;
    import commands.greensock.TweenMaxFrom;
    import commands.greensock.TweenMaxTo;
    import commands.ParallelCommand;
    import commands.SerialCommand;
    import commands.utils.SetProperties;
    import commands.utils.Wait;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.filters.BlurFilter;
    import scenes.Scene;
     
    public class Scene2 extends Scene {
         
        //constant parameters
        private static const IN_TIME:Number = 0.4;
        private static const OUT_TIME:Number = 0.2;
        private static const DELAY_TIME:Number = 0.2;
        private static const BLUR_AMOUNT:Number = 20;
         
        private var container:Sprite;
        private var ss:Scene2Sprite;
        private var blur:BlurFilter;
         
        public function Scene2(container:Sprite) {
            this.container = container;
            ss = new Scene2Sprite();
        }
         
        override public function createIntroCommand():Command {
            var command:Command =
                new ParallelCommand(0,
                     
                    //»…AND»
                    new TweenMaxFrom(ss.text1_mc, IN_TIME, {x:-400}),
                     
                    //»THIS IS»
                    new TweenMaxFrom(ss.text2_mc, IN_TIME, {y:-250, delay:DELAY_TIME}),
                     
                    //»SCENE»
                    new TweenMaxFrom(ss.text3_mc, IN_TIME, {y:250, delay:DELAY_TIME * 2}),
                     
                    //»2″
                    new TweenMaxFrom(ss.text4_mc, IN_TIME, {x:400, delay:DELAY_TIME * 3}),
                     
                    //intro button
                    new SerialCommand(0,
                        new TweenMaxFrom(ss.intro_btn, IN_TIME, {y:250, delay:DELAY_TIME * 4}),
                        new AddEventListener(ss.intro_btn, MouseEvent.CLICK, replayIntro)
                    ),
                     
                    //scene 1 button
                    new SerialCommand(0,
                        new TweenMaxFrom(ss.scene1_btn, IN_TIME, {y:250, delay:DELAY_TIME * 5}),
                        new AddEventListener(ss.scene1_btn, MouseEvent.CLICK, gotoScene1)
                    ),
                     
                    //move the scene 2 sprite to the center of the container
                    new SetProperties(ss, {x:300, y:200}),
                     
                    //add the scene 2 sprite to the container
                    //wait for one frame to allow things to be moved into proper places
                    new SerialCommand(0,
                        new Wait(1 / container.stage.frameRate),
                        new AddChild(container, ss)
                    )
                );
             
            return command;
        }
         
        override public function createOutroCommand():Command {
            var blur:BlurFilter = new BlurFilter(BLUR_AMOUNT, BLUR_AMOUNT, 3);
             
            var command:Command =
                new ParallelCommand(0,
                     
                    //remove display objects
                    new SerialCommand(0,
                        //»THIS»
                        new TweenMaxTo(ss.text1_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
                         
                        //»IS»
                        new TweenMaxTo(ss.text2_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
                         
                        //»SCENE»
                        new TweenMaxTo(ss.text3_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
                         
                        //»2″
                        new TweenMaxTo(ss.text4_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
                         
                        //intro button
                        new TweenMaxTo(ss.intro_btn, OUT_TIME, {alpha:0, blurFilter:blur}),
                         
                        //scene 1 button
                        new TweenMaxTo(ss.scene1_btn, OUT_TIME, {alpha:0, blurFilter:blur}),
                         
                        //remove scene 1 sprite
                        new RemoveChild(container, ss)
                    ),
                     
                    //remove event listeners
                    new RemoveEventListener(ss.intro_btn, MouseEvent.CLICK, replayIntro),
                    new RemoveEventListener(ss.scene1_btn, MouseEvent.CLICK, gotoScene1)
                );
             
            return command;
        }
         
        private function replayIntro(e:Event):void{
            sceneManager.setScene(new IntroScene(container));
        }
         
        private function gotoScene1(e:Event):void{
            sceneManager.setScene(new Scene1(container));
        }
    }
}

Это верно, мы наконец-то закончили! Нажмите CTRL + ENTER в Flash IDE, чтобы протестировать фильм и увидеть плавные и плавные переходы между сценами.


В этом уроке мы создали собственные структуры управления командами и сценами. Мы прошли много кода, но оно того стоит. Теперь, когда у нас есть эти фреймворки, управление сценой осуществляется с помощью легко понятного и поддерживаемого кода. Каждое приложение Flash можно разбить на сцены, и каждая сцена состоит из команд ввода и вывода. Инструкции инкапсулированы в команды, что приводит к единообразному «внешнему виду кода», что позволяет нам управлять входами и выходами сцены на очень высоком уровне.

Надеюсь, вам понравилось, спасибо за чтение!