Advertisement
  1. Code
  2. Workflow

Thinking in Commands: Part 2 of 2

Scroll to top
Read Time: 20 min

During this tutorial we'll further extend the command framework from the first part. We'll create a scene management framework, with easily understandable and maintainable code.


Final Result Preview

Let's take a look at the final result we'll be working towards:


Scene Management

One reasonable approach to break a complete Flash application into smaller pieces is to manage it as separate scenes. The Flash IDE allows you to perform scene management without writing any code, but we're going to approach things completely differently. We will create our own scene management framework.

In our scene management framework, we regard scenes as the smallest building blocks for a complete Flash application. Each scene is comprised of an intro command and an outro command. An intro command initializes everything you need for a scene, such as adding a logo to the display list of your container sprite. An outro command does just the opposite, such as removing the logo from the container sprite. You may view transition from one scene to another as the outro command of the first scene followed by the intro command of the second. In this way, we can put scenes together and manage their transitions very easily.

Take a look at this figure. One scene is just like a piece of a puzzle; the left end representing the intro command, and the right end being the outro command.

Performing a transition from scene A to scene B is just like connecting the two pieces together. The outro command of scene A is executed first, the intro command of scene B is executed next, then the scene transition is complete.

It is basically the exact same concept to perform a transition from scene A to scene C. We just have to put puzzle pieces A and C together, instead of A and B.


Creating Some More Commands

Before we begin building the scene management framework, let's first create some more command classes that will be later used in this tutorial. You can just focus on the overridden execute() methods of the following command classes, which is the most important part of these classes.


GreenSock Tweening Commands

Without a doubt, GreenSock Tweening Platform is one of the best open-source tweening frameworks out there. Scene transitions usually involve lots of tweenings, and GreenSock Tweening Platform has always been my first choice when it comes to creating tweens. We are going to encapsulate this framework into command classes to integrate it with our command framework. Download the TweenMax library, and install it.

We'll be using the to() and from() methods from the TweenMax class. The TweenMax class provides a way to handle the completion of a tween by invoking a function referenced by the optional "onComplete" property in the "vars" parameter. We'll assign the command's complete() method to this property, so the complete() method is invoked when the tween is done. Below is the code for the commands encapsulating these two methods. Create a new directory called "greensock" inside the "commands" directory you created in the first part of this tutorial, and save these classes as TweenMaxTo.as and TweenMaxFrom.as respectively.

1
2
package commands.greensock {
3
	import com.greensock.TweenMax;
4
	import commands.Command;
5
	
6
	//this command encapsulates the TweenMax.to() method

7
	public class TweenMaxTo extends Command {
8
		
9
		public var target:Object;
10
		public var duration:Number;
11
		public var vars:Object;
12
		
13
		public function TweenMaxTo(target:Object, duration:Number, vars:Object) {
14
			this.target = target;
15
			this.duration = duration;
16
			this.vars = vars;
17
		}
18
		
19
		override protected function execute():void {
20
			//tell TweenMax to invoke the command's complete() method when the tweening is done

21
			vars.onComplete = complete;
22
			TweenMax.to(target, duration, vars);
23
		}
24
	}
25
}
1
2
package commands.greensock {
3
	import com.greensock.TweenMax;
4
	import commands.Command;
5
	
6
	//this command encapsulates the TweenMax.from() method

7
	public class TweenMaxFrom extends Command {
8
		
9
		public var target:Object;
10
		public var duration:Number;
11
		public var vars:Object;
12
		
13
		public function TweenMaxFrom(target:Object, duration:Number, vars:Object) {
14
			this.target = target;
15
			this.duration = duration;
16
			this.vars = vars;
17
		}
18
		
19
		override protected function execute():void {
20
			//tell TweenMax to invoke the command's complete() method when the tweening is done

21
			vars.onComplete = complete;
22
			TweenMax.from(target, duration, vars);
23
		}
24
	}
25
}

(Be sure to re-read my introduction to commands if you need to refresh your memory.)

TweenMaxTo will tween the target object from its current position (or blur, or alpha, or ...) to the new position (etc) that you specify with the vars object. TweenMaxFrom does the opposite.

If you're familiar enough with the GreenSock Tweening Platform, you might also want to encapsulate the TweenLite and TweenNano classes to fit your needs.


Display Object Container Commands

As previously mentioned, the intro and outro of a scene may very likely involve adding display objects to a display object container and removing the objects from the container. So here let's encapsulate the addChild() and removeChild() methods into commands.

1
2
package commands.display {
3
	import commands.Command;
4
	import flash.display.DisplayObject;
5
	import flash.display.DisplayObjectContainer;
6
	
7
	//This command encapsulates the addChild() method

8
	public class AddChild extends Command {
9
		
10
		public var container:DisplayObjectContainer;
11
		public var displayObject:DisplayObject
12
		
13
		public function AddChild(container:DisplayObjectContainer, displayObject:DisplayObject) {
14
			this.container = container;
15
			this.displayObject = displayObject;
16
		}
17
		
18
		override protected function execute():void {
19
			container.addChild(displayObject);
20
			complete();
21
		}
22
	}
23
}
1
2
package commands.display {
3
	import commands.Command;
4
	import flash.display.DisplayObject;
5
	import flash.display.DisplayObjectContainer;
6
	
7
	//This command encapsulates the removeChild() method

8
	public class RemoveChild extends Command {
9
		
10
		public var container:DisplayObjectContainer;
11
		public var displayObject:DisplayObject
12
		
13
		public function RemoveChild(container:DisplayObjectContainer, displayObject:DisplayObject) {
14
			this.container = container;
15
			this.displayObject = displayObject;
16
		}
17
		
18
		override protected function execute():void {
19
			container.removeChild(displayObject);
20
			complete();
21
		}
22
	}
23
}

Event Listener Commands

We'll also be using commands to handle the adding and removing of event listeners, so let's encapsulate the addEventListener() and removeEventListener() methods.

1
2
package commands.events {
3
	import commands.Command;
4
	import flash.events.IEventDispatcher;
5
	
6
	//this command encapsulates the addEventListener() method

7
	public class AddEventListener extends Command {
8
		
9
		public var dispatcher:IEventDispatcher;
10
		public var type:String;
11
		public var listener:Function;
12
		
13
		public function AddEventListener(dispatcher:IEventDispatcher, type:String, listener:Function) {
14
			this.dispatcher = dispatcher;
15
			this.type = type;
16
			this.listener = listener;
17
		}
18
		
19
		override protected function execute():void {
20
			dispatcher.addEventListener(type, listener);
21
			complete();
22
		}
23
	}
24
}
1
2
package commands.events {
3
	import commands.Command;
4
	import flash.events.IEventDispatcher;
5
	
6
	//this command encapsulates the removeEventListener() method

7
	public class RemoveEventListener extends Command {
8
		
9
		public var dispatcher:IEventDispatcher;
10
		public var type:String;
11
		public var listener:Function;
12
		
13
		public function RemoveEventListener(dispatcher:IEventDispatcher, type:String, listener:Function) {
14
			this.dispatcher = dispatcher;
15
			this.type = type;
16
			this.listener = listener;
17
		}
18
		
19
		override protected function execute():void {
20
			dispatcher.removeEventListener(type, listener);
21
			complete();
22
		}
23
	}
24
}

Utility Commands

Finally, we'll need some utility commands to make things easier. The SetProperties command sets an object's properties from another object's property values:

1
2
package commands.utils {
3
	import commands.Command;
4
	
5
	//this command sets an object's properties in a quick and convenient way

6
	public class SetProperties extends Command {
7
		
8
		public var target:Object;
9
		public var properties:Object;
10
		
11
		public function SetProperties(target:Object, properties:Object) {
12
			this.target = target;
13
			this.properties = properties;
14
		}
15
		
16
		override protected function execute():void {
17
			for (var key:String in properties) {
18
				target[key] = properties[key];
19
			}
20
			complete();
21
		}
22
	}
23
}

We can use it like this:

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

...and it will set the x and y properties of the target object to the values specified.

The Dummy command simply does nothing and completes the command execution. The purpose of this command is to serve as a "placeholder" and shall become clear later on:

1
2
package commands.utils {
3
	import commands.Command;
4
	
5
	//this command simply does nothing and completes itself upon execution

6
	public class Dummy extends Command {
7
		
8
		public function Dummy() {
9
			
10
		}
11
		
12
		override protected function execute():void {
13
			complete();
14
		}
15
	}
16
}

The Wait command waits for a specified amount of delay time and then completes the command execution without doing anything:

1
2
package commands.utils {
3
	import commands.Command;
4
	
5
	public class Wait extends Command {
6
		
7
		public function Wait(delay:Number = 0) {
8
			super(delay);
9
		}
10
		
11
		override protected function execute():void {
12
			complete();
13
		}
14
	}
15
}

You might wonder why we would need a command that simply occupies time if we already have a "delay" constructor parameter in the base Command class. Sometimes we'd like to design constructors to only have parameters that really have something to do with the command's specific functionality, and including the "delay" time as one parameter amongst them is kind of interrupting the "uniformity" in terms of parameter purposes. So instead of writing the code below:

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

We could write something like this:

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

The "delay" parameters no longer unnecessarily catch your eyes in the SomeFancyCommand constructors. They have now been moved to the Wait commands to make things cleaner.


The Scene Management Framework

Here's our Scene class, representing a single "puzzle piece". What each method does is explained in the comments. This class is pretty much a "skeleton" class, since every method either creates a dummy command or does nothing. To get things juicier, these methods have to be overridden. Create a new "scenes" directory in your project's source folder to store these new classes:

1
2
package scenes {
3
	import commands.Command;
4
	import commands.utils.Dummy;
5
	
6
	//this class represents a scene for a complete Flash application

7
	public class Scene {
8
		
9
		//a reference to the scene manager owning this scene

10
		internal var _sceneManager:SceneManager;
11
		protected final function get sceneManager():SceneManager { return _sceneManager; }
12
		
13
		//creates the intro command of this scene

14
		public function createIntroCommand():Command {
15
			return new Dummy();
16
		}
17
		
18
		//creates the outro command of this scene

19
		public function createOutroCommand():Command {
20
			return new Dummy();
21
		}
22
		
23
		//handle scene-related stuff here when the scene is set

24
		public function onSceneSet():void {
25
			
26
		}
27
	}
28
}

And here's the SceneManager class that handles scene transitions, details also explained in the comments. Note that I've added a "dummy-proof variable" to protect transitions from being broken by untimely invocation to the setScene() method.

1
2
package scenes {
3
	import commands.Command;
4
	import flash.events.Event;
5
	
6
	//this class handles scene transitions

7
	public class SceneManager {
8
		
9
		//a reference to the current scene

10
		private var _currentScene:Scene;
11
		
12
		//a reference to the target scene of a transition

13
		private var _targetScene:Scene;
14
		
15
		//dummy-proof variable

16
		private var _isInTransition:Boolean = false;
17
		
18
		public function SceneManager() {
19
			
20
		}
21
		
22
		public function setScene(scene:Scene):void {
23
			//if a transition is not finished, ignore the method invocation

24
			if (_isInTransition) return;
25
			
26
			_targetScene = scene;
27
			
28
			//turn on the dummy-proof variable

29
			_isInTransition = true;
30
			
31
			//check if a scene is already assigned to the scene manager

32
			if (_currentScene) {
33
				
34
				//if yes, start the outro of the current scene first

35
				var outroCommand:Command = _currentScene.createOutroCommand();
36
				
37
				//and listen for the complete event of the outro command

38
				outroCommand.addEventListener(Event.COMPLETE, onCurrentOutroComplete);
39
				outroCommand.start();
40
				
41
			} else {
42
				//if not, start the intro of the target scene

43
				gotoTargetScene();
44
			}
45
		}
46
		
47
		//invoked when the outro command of the current scene is complete

48
		private function onCurrentOutroComplete(e:Event):void {
49
			Command(e.target).removeEventListener(Event.COMPLETE, onCurrentOutroComplete);
50
			gotoTargetScene();
51
		}
52
		
53
		private function gotoTargetScene():void {
54
			//set the scene manager reference of the target scene to this

55
			_targetScene._sceneManager = this;
56
			
57
			var introCommand:Command = _targetScene.createIntroCommand();
58
			
59
			//listen for the complete event of the intro command of the target scene

60
			introCommand.addEventListener(Event.COMPLETE, onTargetIntroComplete);
61
			introCommand.start();
62
		}
63
		
64
		//invoked when the intro command of the target scene is complete

65
		private function onTargetIntroComplete(e:Event):void {
66
			Command(e.target).removeEventListener(Event.COMPLETE, onTargetIntroComplete);
67
			
68
			//remove the scene manager reference of the previous scene

69
			if (_currentScene) _currentScene._sceneManager = null;
70
			
71
			//set the target scene as the current scene

72
			_currentScene = _targetScene;
73
			
74
			//turn off the dummy-proof variable

75
			_isInTransition = false;
76
			
77
			//and invoke the onSceneSet() method

78
			_currentScene.onSceneSet();
79
		}
80
	}
81
}

Okay. Everything's set and we're ready to go. It's time to create an actual application with the framework we've built.


Step 1: Create a Flash Document

Open the Flash IDE and create a new Flash document. Name it "SceneTransitions" and create a document class of the same name. Also, you can place a background on the stage if you like.


Step 2: Create Intro Text

Create 4 symbols with text and name them according to the following image. Throughout this example, export every symbol for ActionScript with a class name that's the same as its symbol name.


Step 3: Create Scene 1

Create symbols and name them as shown in the following image. Also, layout their instances and name them as shown. Select all the instances and convert them, as a group, to another symbol, named "Scene1Sprite." You can then delete the Scene1Sprite from the stage (but not from the library).


Step 4: Create Scene 2

Do exactly the same as the previous step, but this time select all of the instances and convert them to a symbol named "Scene2Sprite."


Step 5: The Document Class

The document class is surprisingly simple. Just create a scene manager and tell the manager to set the current scene to an intro scene.

1
2
package {
3
	import flash.display.Sprite;
4
	import scenes.SceneManager;
5
	
6
	public class SceneTransitions extends Sprite {
7
		
8
		public function SceneTransitions() {
9
			var sceneManager:SceneManager = new SceneManager();
10
			sceneManager.setScene(new IntroScene(this));
11
		}
12
	}
13
}

Step 6: Create the Intro Scene

The initial scene we set for the scene manager is an intro scene. As its name suggests, this scene is simply an intro to our main scene (rather than being the intro portion of our main scene's "puzzle piece"). The intro command (created from the override createIntroCommand() method) of this intro scene moves instances of symbols to the center of the stage (by the SetProperties command), adds them to the container, tweens them from zero scale to 100% scale, and blurs them out to zero alpha, one-after-another. This is achieved by linking all the separate commands together with a single serial command (as you should remember from Part One).

When the intro command is complete, the onSceneSet() method is invoked, and at this point the sceneManager property is available, and its setScene() method can be invoked to switch scene. In the onSceneSet() method, the scene manager's setScene() method is invoked to change to Scene1 (a class we will create in the next step). As we didn't override the createOutroCommand(), the outro command of the intro scene is a dummy command, which does nothing.

1
2
package {
3
	import commands.Command;
4
	import commands.display.AddChild;
5
	import commands.display.RemoveChild;
6
	import commands.greensock.TweenMaxFrom;
7
	import commands.greensock.TweenMaxTo;
8
	import commands.scenes.SetScene;
9
	import commands.SerialCommand;
10
	import commands.utils.SetProperties;
11
	import flash.display.DisplayObject;
12
	import flash.display.Sprite;
13
	import flash.filters.BlurFilter;
14
	import scenes.Scene;
15
	
16
	public class IntroScene extends Scene {
17
		
18
		//constant parameters

19
		private static const ZOOM_IN_TIME:Number = 0.2;
20
		private static const HOLD_TIME:Number = 0.3;
21
		private static const BLUR_OUT_TIME:Number = 0.2;
22
		private static const BLUR_AMOUNT:Number = 20;
23
		
24
		private var container:Sprite;
25
		
26
		public function IntroScene(container:Sprite) {
27
			this.container = container;
28
		}
29
		
30
		override public function createIntroCommand():Command {
31
			var blur:BlurFilter = new BlurFilter(BLUR_AMOUNT, BLUR_AMOUNT, 2);
32
			
33
			//symbol instances

34
			var text1:DisplayObject = new IntroText1();
35
			var text2:DisplayObject = new IntroText2();
36
			var text3:DisplayObject = new IntroText3();
37
			var text4:DisplayObject = new IntroText4();
38
			
39
			//this is the serial command that links things together

40
			var command:Command =
41
				new SerialCommand(0,
42
					
43
					//"THIS"

44
					new SetProperties(text1, {x:320, y:200}),
45
					new AddChild(container, text1),
46
					new TweenMaxFrom(text1, ZOOM_IN_TIME, {scaleX:0, scaleY:0}),
47
					new TweenMaxTo(text1, BLUR_OUT_TIME, {delay:HOLD_TIME, alpha:0, blurFilter:blur}),
48
					new RemoveChild(container, text1),
49
					
50
					//"IS"

51
					new SetProperties(text2, {x:320, y:200}),
52
					new AddChild(container, text2),
53
					new TweenMaxFrom(text2, ZOOM_IN_TIME, {scaleX:0, scaleY:0}),
54
					new TweenMaxTo(text2, BLUR_OUT_TIME, {delay:HOLD_TIME, alpha:0, blurFilter:blur}),
55
					new RemoveChild(container, text2),
56
					
57
					//"AN"

58
					new SetProperties(text3, {x:320, y:200}),
59
					new AddChild(container, text3),
60
					new TweenMaxFrom(text3, ZOOM_IN_TIME, {scaleX:0, scaleY:0}),
61
					new TweenMaxTo(text3, BLUR_OUT_TIME, {delay:HOLD_TIME, alpha:0, blurFilter:blur}),
62
					new RemoveChild(container, text3),
63
					
64
					//"INTRO"

65
					new SetProperties(text4, {x:320, y:200}),
66
					new AddChild(container, text4),
67
					new TweenMaxFrom(text4, ZOOM_IN_TIME, {scaleX:0, scaleY:0}),
68
					new TweenMaxTo(text4, BLUR_OUT_TIME, {delay:HOLD_TIME, alpha:0, blurFilter:blur}),
69
					new RemoveChild(container, text4),
70
				);
71
			
72
			return command;
73
		}
74
		
75
		override public function onSceneSet():void {
76
			//when the scene is set, directly go to scene 1

77
			sceneManager.setScene(new Scene1(container));
78
		}
79
	}
80
}

You can adjust the value of the consts to alter the tweening effects.


Step 7: Create Scene1

Now let's look at the Scene1 class. The text fields are tweened into position one-by-one; the "intro_btn" and "scene2_btn" buttons are registered with mouse-click event listeners after being tweened into position, achieved by chaining together the commands for tweening and adding listeners with a serial command.

Another thing worth mentioning is the AddChild command that adds the Scene1Sprite to the container. It is concatenated in series after a Wait command that waits for one frame. Because the TweenMax class updates all display objects in the next frame after the call to the TweenMax.from() method, sometimes you may see a quick "glimpse" of objects in their final places, before the tweening starts. The purpose of the Wait command here is to give TweenMax enough time to move objects into their proper starting places.

1
2
package  {
3
	import commands.Command;
4
	import commands.display.AddChild;
5
	import commands.display.RemoveChild;
6
	import commands.events.AddEventListener;
7
	import commands.events.RemoveEventListener;
8
	import commands.greensock.TweenMaxFrom;
9
	import commands.greensock.TweenMaxTo;
10
	import commands.ParallelCommand;
11
	import commands.SerialCommand;
12
	import commands.utils.SetProperties;
13
	import commands.utils.Wait;
14
	import flash.display.Sprite;
15
	import flash.events.Event;
16
	import flash.events.MouseEvent;
17
	import flash.filters.BlurFilter;
18
	import scenes.Scene;
19
	
20
	public class Scene1 extends Scene {
21
		
22
		//constant parameters

23
		private static const IN_TIME:Number = 0.4;
24
		private static const OUT_TIME:Number = 0.2;
25
		private static const DELAY_TIME:Number = 0.2;
26
		private static const BLUR_AMOUNT:Number = 20;
27
		
28
		private var container:Sprite;
29
		private var ss:Scene1Sprite;
30
		private var blur:BlurFilter;
31
		
32
		public function Scene1(container:Sprite) {
33
			this.container = container;
34
			ss = new Scene1Sprite();
35
		}
36
		
37
		override public function createIntroCommand():Command {
38
			var command:Command =
39
				new ParallelCommand(0,
40
					
41
					//"THIS"

42
					new TweenMaxFrom(ss.text1_mc, IN_TIME, {x:-400}),
43
					
44
					//"IS"

45
					new TweenMaxFrom(ss.text2_mc, IN_TIME, {y:-250, delay:DELAY_TIME}),
46
					
47
					//"SCENE"

48
					new TweenMaxFrom(ss.text3_mc, IN_TIME, {y:250, delay:DELAY_TIME * 2}),
49
					
50
					//"1"

51
					new TweenMaxFrom(ss.text4_mc, IN_TIME, {x:400, delay:DELAY_TIME * 3}),
52
					
53
					//intro button

54
					new SerialCommand(0,
55
						new TweenMaxFrom(ss.intro_btn, IN_TIME, {y:250, delay:DELAY_TIME * 4}),
56
						new AddEventListener(ss.intro_btn, MouseEvent.CLICK, replayIntro)
57
					),
58
					
59
					//scene 2 button

60
					new SerialCommand(0,
61
						new TweenMaxFrom(ss.scene2_btn, IN_TIME, {y:250, delay:DELAY_TIME * 5}),
62
						new AddEventListener(ss.scene2_btn, MouseEvent.CLICK, gotoScene2)
63
					),
64
					
65
					//move the scene 1 sprite to the center of the container

66
					new SetProperties(ss, {x:300, y:200}),
67
					
68
					//add the scene 1 sprite to the container

69
					//wait for one frame to allow things to be moved into proper places

70
					new SerialCommand(0,
71
						new Wait(1 / container.stage.frameRate),
72
						new AddChild(container, ss)
73
					)
74
				);
75
			
76
			return command;
77
		}
78
		
79
		override public function createOutroCommand():Command {
80
			var blur:BlurFilter = new BlurFilter(BLUR_AMOUNT, BLUR_AMOUNT, 3);
81
			
82
			var command:Command =
83
				new ParallelCommand(0,
84
					
85
					//remove display objects

86
					new SerialCommand(0,
87
						//"THIS"

88
						new TweenMaxTo(ss.text1_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
89
						
90
						//"IS"

91
						new TweenMaxTo(ss.text2_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
92
						
93
						//"SCENE"

94
						new TweenMaxTo(ss.text3_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
95
						
96
						//"1"

97
						new TweenMaxTo(ss.text4_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
98
						
99
						//intro button

100
						new TweenMaxTo(ss.intro_btn, OUT_TIME, {alpha:0, blurFilter:blur}),
101
						
102
						//scene 2 button

103
						new TweenMaxTo(ss.scene2_btn, OUT_TIME, {alpha:0, blurFilter:blur}),
104
						
105
						//remove scene 1 sprite

106
						new RemoveChild(container, ss)
107
					),
108
					
109
					//remove event listeners

110
					new RemoveEventListener(ss.intro_btn, MouseEvent.CLICK, replayIntro),
111
					new RemoveEventListener(ss.scene2_btn, MouseEvent.CLICK, gotoScene2)
112
				);
113
			
114
			return command;
115
		}
116
		
117
		private function replayIntro(e:Event):void{
118
			sceneManager.setScene(new IntroScene(container));
119
		}
120
		
121
		private function gotoScene2(e:Event):void{
122
			sceneManager.setScene(new Scene2(container));
123
		}
124
	}
125
}

Step 8: Create Scene2

The Scene2 class looks pretty much like Scene1; though some text is changed:

1
2
package  {
3
	import commands.Command;
4
	import commands.display.AddChild;
5
	import commands.display.RemoveChild;
6
	import commands.events.AddEventListener;
7
	import commands.events.RemoveEventListener;
8
	import commands.greensock.TweenMaxFrom;
9
	import commands.greensock.TweenMaxTo;
10
	import commands.ParallelCommand;
11
	import commands.SerialCommand;
12
	import commands.utils.SetProperties;
13
	import commands.utils.Wait;
14
	import flash.display.Sprite;
15
	import flash.events.Event;
16
	import flash.events.MouseEvent;
17
	import flash.filters.BlurFilter;
18
	import scenes.Scene;
19
	
20
	public class Scene2 extends Scene {
21
		
22
		//constant parameters

23
		private static const IN_TIME:Number = 0.4;
24
		private static const OUT_TIME:Number = 0.2;
25
		private static const DELAY_TIME:Number = 0.2;
26
		private static const BLUR_AMOUNT:Number = 20;
27
		
28
		private var container:Sprite;
29
		private var ss:Scene2Sprite;
30
		private var blur:BlurFilter;
31
		
32
		public function Scene2(container:Sprite) {
33
			this.container = container;
34
			ss = new Scene2Sprite();
35
		}
36
		
37
		override public function createIntroCommand():Command {
38
			var command:Command =
39
				new ParallelCommand(0,
40
					
41
					//"...AND"

42
					new TweenMaxFrom(ss.text1_mc, IN_TIME, {x:-400}),
43
					
44
					//"THIS IS"

45
					new TweenMaxFrom(ss.text2_mc, IN_TIME, {y:-250, delay:DELAY_TIME}),
46
					
47
					//"SCENE"

48
					new TweenMaxFrom(ss.text3_mc, IN_TIME, {y:250, delay:DELAY_TIME * 2}),
49
					
50
					//"2"

51
					new TweenMaxFrom(ss.text4_mc, IN_TIME, {x:400, delay:DELAY_TIME * 3}),
52
					
53
					//intro button

54
					new SerialCommand(0,
55
						new TweenMaxFrom(ss.intro_btn, IN_TIME, {y:250, delay:DELAY_TIME * 4}),
56
						new AddEventListener(ss.intro_btn, MouseEvent.CLICK, replayIntro)
57
					),
58
					
59
					//scene 1 button

60
					new SerialCommand(0,
61
						new TweenMaxFrom(ss.scene1_btn, IN_TIME, {y:250, delay:DELAY_TIME * 5}),
62
						new AddEventListener(ss.scene1_btn, MouseEvent.CLICK, gotoScene1)
63
					),
64
					
65
					//move the scene 2 sprite to the center of the container

66
					new SetProperties(ss, {x:300, y:200}),
67
					
68
					//add the scene 2 sprite to the container

69
					//wait for one frame to allow things to be moved into proper places

70
					new SerialCommand(0,
71
						new Wait(1 / container.stage.frameRate),
72
						new AddChild(container, ss)
73
					)
74
				);
75
			
76
			return command;
77
		}
78
		
79
		override public function createOutroCommand():Command {
80
			var blur:BlurFilter = new BlurFilter(BLUR_AMOUNT, BLUR_AMOUNT, 3);
81
			
82
			var command:Command =
83
				new ParallelCommand(0,
84
					
85
					//remove display objects

86
					new SerialCommand(0,
87
						//"THIS"

88
						new TweenMaxTo(ss.text1_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
89
						
90
						//"IS"

91
						new TweenMaxTo(ss.text2_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
92
						
93
						//"SCENE"

94
						new TweenMaxTo(ss.text3_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
95
						
96
						//"2"

97
						new TweenMaxTo(ss.text4_mc, OUT_TIME, {alpha:0, blurFilter:blur}),
98
						
99
						//intro button

100
						new TweenMaxTo(ss.intro_btn, OUT_TIME, {alpha:0, blurFilter:blur}),
101
						
102
						//scene 1 button

103
						new TweenMaxTo(ss.scene1_btn, OUT_TIME, {alpha:0, blurFilter:blur}),
104
						
105
						//remove scene 1 sprite

106
						new RemoveChild(container, ss)
107
					),
108
					
109
					//remove event listeners

110
					new RemoveEventListener(ss.intro_btn, MouseEvent.CLICK, replayIntro),
111
					new RemoveEventListener(ss.scene1_btn, MouseEvent.CLICK, gotoScene1)
112
				);
113
			
114
			return command;
115
		}
116
		
117
		private function replayIntro(e:Event):void{
118
			sceneManager.setScene(new IntroScene(container));
119
		}
120
		
121
		private function gotoScene1(e:Event):void{
122
			sceneManager.setScene(new Scene1(container));
123
		}
124
	}
125
}

Test the Movie

That's right, we're finally finished! Press CTRL+ENTER in the Flash IDE to test the movie and see the smooth and seamless transitions between scenes.


Conclusion

In this tutorial we've built our own command and scene management frameworks. We've gone through a whole lot of code, but it's totally worth it. Now that we have these frameworks at hand, scene management is done with easily understandable and maintainable code. Each Flash application can be broken down into scenes, and each scene consists of intro and outro commands. Instructions are encapsulated into commands, resulting in uniform "code appearance", which allows us to manage scene intro and outro in a very high-level way.

I hope you enjoyed it, thanks for reading!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.