Simplify Flow Between Game Screens with the “Scene System”

by Michael James Williams on April 13, 2009 · 27 comments

in Useful Classes

Transparent screen
Photo by motoyen.

Every Flash game is split up into different screens: loading screen, play screen, credits screen, menu screen, options screen, cutscene screen, and so on. Switching between these is such a crucial, yet simple, task that it makes no sense to rewrite the code afresh every time you start a new game (let alone every time you add a new screen to an existing game!) Here’s what you can do instead.

Paul over at RiverMan Media has written a great article on the solution he came up with for the games he makes. He calls it the Scene System. I really recommend reading how it solves the common problems faced by anyone trying to figure out a way of managing their screens: check it out here.

Although the ideas in the article do apply to AS3, the example code is written in Java, and there are a few points we’ll have to watch out for when translating it. In this post, I’ll show you my conversion, and how to use it.

Scene –> GameScene

The first point’s a small one: Flash already has its own concept of Scenes. Essentially, a MovieClip can be broken down into “chunks” of frames — scenes — and AS3 has various methods for checking which scene a MovieClip is currently in, and moving to a different scene.

I don’t recommend using scenes when writing game code as they tend to cause more trouble than they’re worth, but since they’re in the language we shouldn’t use them. So, whenever there’s the possibility of confusion, I’ll call them GameScenes. We can get away with referring to them as just plain old “scenes” most of the time, though.

Abstract –> Interface

Unlike Java, Flash does not have such a thing as abstract classes (classes that can never be instantiated, but can be extended). The closest thing we have is an interface, basically a list of functions, their parameters, and their return types.

As Richard Davey of PhotonStorm put it, implementing an interface is like making a promise; you promise that the class implementing the interface will contain all of the functions defined by the list. An interface does not explain how exactly the functions should work, though.

Let me explain by example. Here’s my version of Paul’s abstract Scene class:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.michaeljameswilliams.gamedev.gamescenes 
{
 
	/**
	 * Based on http://www.rivermanmedia.com/programming/6-object-oriented-game-programming-the-scene-system
	 * More info: http://gamedev.michaeljameswilliams.com/2009/04/13/as3-scene-system/
	 * @author MichaelJWilliams
	 */
 
	public interface IGameScene 
	{
		/**
		 * Update logic for this game scene.
		 */
		function update():void;
		/**
		 * Redraw everything on screen.
		 */
		function redraw():void;
		/**
		 * Load all of the data and graphics that this scene needs to function.
		 */
		function load():void;
		/**
		 * Unload everything that the garbage collector won't unload itself, including graphics.
		 */
		function unload():void;
	}
 
}

The first thing to note is that I’ve called it IGameScene. It’s convention to start the name of an interface with a capital I, and as I explained above, we should prefer GameScene to Scene wherever there’s ambiguity.

To use this, we need to do is write implements IGameScene after the class definition of anything we want to use as a scene. For example, suppose we have a class MenuScene that extends MovieClip:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package  
{
	import flash.display.MovieClip;
 
	public class MenuScreen extends MovieClip
	{
 
		public function MenuScreen() 
		{
 
		}
 
	}
 
}

…we have to add implements IGameScreen after extends MovieClip:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package  
{
	import com.michaeljameswilliams.gamedev.gamescenes.IGameScene;
	import flash.display.MovieClip;
 
	public class MenuScreen extends MovieClip implements IGameScene
	{
 
		public function MenuScreen() 
		{
 
		}
 
	}
 
}

…(and import IGameScene as well, naturally.) Now we need to fulfil our promise by creating four public functions to match the ones defined in IGameScene:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
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
package  
{
	import com.michaeljameswilliams.gamedev.gamescenes.IGameScene;
	import flash.display.MovieClip;
 
	public class MenuScreen extends MovieClip implements IGameScene
	{
 
		public function MenuScreen() 
		{
 
		}
 
		public function update():void
		{
 
		}
 
		public function redraw():void
		{
 
		}
 
		public function load():void
		{
 
		}
 
		public function unload():void 
		{
 
		}
	}
 
}

The comments in the interface class itself explain what each of these functions should do.

Alternatively, we could have created a class GameScene that extended, say, MovieClip and contained these four empty functions, and then have every specific scene extend GameScene and override each function. The trouble with that is, if you want a scene to extend Sprite or Bitmap instead of MovieClip, you’re stuck.

Using this interface, we could create three new classes: GameSceneMovieClip, GameSceneSprite and GameSceneBitmap, each extending a different base class and implementing the four IGameScene functions in their own way. Each specific scene could then extend the most fitting class, and then just inherit the four functions without overriding them.

SceneManager –> GameSceneManager

There’s not much that needed changing here. The code is quite long, so I’ve collapsed it; click the little triangle to show it all:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
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
81
82
83
84
85
86
87
88
89
90
91
92
93
package com.michaeljameswilliams.gamedev.gamescenes 
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
 
	/**
	 * Based on http://www.rivermanmedia.com/programming/6-object-oriented-game-programming-the-scene-system
	 * More info: http://gamedev.michaeljameswilliams.com/2009/04/13/as3-scene-system/
	 * Singleton template from here: http://www.gskinner.com/blog/archives/2006/07/as3_singletons.html
	 * @author MichaelJWilliams
	 */
 
	public class GameSceneManager {
		private static var _instance:GameSceneManager;
		private static var _allowInstantiation:Boolean;
		private static var _currentScene:IGameScene;
		private static var _sceneContainer:DisplayObjectContainer;
 
		public static function getInstance( p_sceneContainer:DisplayObjectContainer = null ):GameSceneManager 
		{
			if ( _instance == null ) 
			{
				_allowInstantiation = true;
				_instance = new GameSceneManager();
				_allowInstantiation = false;
			}
 
			if ( p_sceneContainer )
			{
				setSceneContainer( p_sceneContainer );
			}
 
			return _instance;
		}
 
		/**
		 * 
		 * @param	p_sceneContainer	Object that is parent of each scene -- for example, the document class
		 */
		public function GameSceneManager():void 
		{
			if ( !_allowInstantiation ) 
			{
				throw new Error("Error: Instantiation failed: Use GameSceneManager.getInstance() instead of new.");
			}
		}
 
		public static function setSceneContainer( p_sceneContainer:DisplayObjectContainer ):void
		{
			_sceneContainer = p_sceneContainer;
		}
 
		/**
		 * Update logic for the current scene.
		 */
		public static function update():void
		{
			_currentScene.update();
		}
 
		/**
		 * Redraw everything on screen.
		 */
		public static function redraw():void
		{
			_currentScene.redraw();
		}
 
		/**
		 * A simplified way of loading and unloading scenes
		 * Notice that the method is static so that anyone can call it.
		 * @param	p_newScene	The scene to switch to.
		 */
		public static function changeScene( p_newScene:IGameScene ):void
		{
			if ( ( p_newScene is DisplayObject ) && ( _sceneContainer ) )
			{
				if ( _currentScene != null )
				{
					_sceneContainer.removeChild( _currentScene as DisplayObject );
					_currentScene.unload();
				}
				p_newScene.load();
				_currentScene = p_newScene;
				_sceneContainer.addChild( _currentScene as DisplayObject );
			}
			else
			{
				throw new Error("Error: game scenes must be of type DisplayObject and scene container must be set.");
			}
		}
	}
}

The most notable change is the addition of a _sceneContainer variable. As you can see in lines 80 and 85, this is the DisplayObjectContainer to which each scene is added as a child.

The other addition worth mentioning is in line 76, where the scene is checked to see whether it is a DisplayObject. If it’s not, it can’t be added to the scene container, so it throws an error.

Using the Scene System

Step 1: Download the zip file from here. Extract it to your regular classpath directory — or if you don’t have one, to whatever directory your FLA is in.

Step 2: Decide which screens should be scenes (see Paul’s article for help) and have them each implement IGameScene. Remember, this involves importing com.michaeljameswilliams.gamedev.gamescenes.IGameScene, as well as creating the four functions.

Step 3: In your document class, import com.michaeljameswilliams.gamedev.gamescenes.GameSceneManager, and define a class-scope variable to hold the instance:

?View Code ACTIONSCRIPT3
public var gameSceneManagerInstance:GameSceneManager;

Then, in your constructor function, initalise the manager:

?View Code ACTIONSCRIPT3
gameSceneManagerInstance = GameSceneManager.getInstance( this );

Using this as the parameter will set the document class as the scene container.

Step 4: Whenever you want to change scenes, just call GameSceneManager.changeScene() with the scene you want to switch to. (Note that this is a function of GameSceneManager, not gameSceneManagerInstance.) You have to create and instantiate the scene first, of course:

?View Code ACTIONSCRIPT3
var menuScene:MenuScene = new MenuScene();
GameSceneManager.changeScene( menuScene );

That’s it! The GameSceneManager takes care of the rest. And because it’s a static class, you can call it from anywhere — even from within a scene.

Going Further

Although this is very convenient, at the minute it’s a little basic. One great addition we could include is automated transitions. I’ll talk about this in a future post. (If you don’t want to miss it, why not sign up for email updates? ;) )

In the mean time, I’ve modified the files from my AS3 Avoider Game Tutorial to use the scene system. It’s a little messy because I didn’t design the code with this system in mind, but it works. You can download it from here. Feel free to take it apart :)

Thanks to Paul for letting me write this. Any questions? Stick them in the comments!

{ 27 comments… read them below or add one }

spoon April 13, 2009 at 11:17 pm

For all my simple/quick games, I made a template with loading, mochiads, menu, highscore screens etc.

All I then gotta do is work on the game itself, which is in it’s one file. I edit the mochiads id number, mochiads highscores id, and other highscore apis that I have implemented. Then just replace the graphics, meaning the title, buttons, background, which is just done in the Flash IDE, with no programming needed.

I made it easy to change the transition method used between screens, so I can make it slide to the side, zoom or just change or whatever.

So besides the game itself, there’s just a few minutes of work, and no programming to be done. Basically just skinning.

For bigger, very nice games, I make it all from scratch (of course reusing functions and classes if I can), because they deserve the little times it takes to make a complete custom system that fits them exactly. (Mostly just skinning my template is enough though).

MichaelJWilliams April 13, 2009 at 11:36 pm

That sounds really streamlined. Nice. I’d love to see an example, if you’re happy to share it.

How do you keep all the game-specific code in one file, though?

Paolo April 14, 2009 at 7:10 am

I can’t tell you how much my code in Strike Eagle would have been seriously improved had I known about this. I used the “Scenes” in Flash which put everything into the main timeline of the application. So all my buttons and animation logic were all in the Main Document class.

Drove me nuts.

Snurre April 14, 2009 at 1:50 pm

Nice tutorial once again :)

@ Spoon: as MJW, I’d love to see this if I you would show us. I guess you would still make classes and stuff (or could if you would), not just having one ActionScript file for all of the game logic?

MichaelJWilliams April 14, 2009 at 2:45 pm

Thanks guys :)

Paolo: Huh, I’m surprised at that. It all seems really smooth and well-separated to me. How did you separate the different screens of the game?

Kronosfere April 20, 2009 at 5:56 am

Dang. I’ve learnt abit of Java before using this method and went on to forget about it >.> It’s definitely much cleaner than the way I’m swapping between my scenes now.
I made use of 2 switches. 1 to dump the current scene and 1 to add the new scene. A really simple system except you have to make an individual case for each scene.

Mushyrulez August 17, 2009 at 4:49 am

O_o epic awesome!

Wouldn’t it also be smoother to put the addChild and removeChild functions inside GameSceneManager? Somehow save the scene’s name and removeChild that, then you would only need to call GameSceneManager.changeScene( menuScene );, or maybe something like GameSceneManager.changeScene( menuScene, playScene );, with the first being the current scene, and the second being the one to change into? You could take their names and removeChild/addChild the respective scenes.

Also, i didn’t really see any modifications inside the avoider game tutorial :P However, if you did modify it to use this (and I really really suck at observations, which I do -_-), I think it would be better not to, for your tutorial is more about one to learn AS3, and the updates can be added after the base tutorial is finished.

Great system; I look forward to t3h next post!

Michael Williams August 18, 2009 at 12:14 am

Thanks, Mushyrulez, and good to see you back, if I haven’t said that already :)

Actually, the GameSceneManager does contain the addChild() and removeChild() calls. It just calls them on _sceneContainer, like _sceneContainer.addChild().

I have modified this a fair bit since I wrote this article, but every time I go to write it up as a blog post, I change it again! :P

Oh, no no, I didn’t modify the base tutorial; I meant that I made a copy of the tutorial and applied the Scene system to that copy. You can grab that here, if you want to see it in action.

Mushyrulez August 18, 2009 at 3:18 am

Ah, I see :D

Something’s not working with the .swf though; I can’t move the avatar. Do you know what’s happening?
(the .swf with your base tutorial implementing the scene system, I mean; mine’s working flawlessly :D )

Michael Williams August 18, 2009 at 5:30 pm

Huh, that’s weird, it works fine for me. What version of Flash Player do you have?

crila January 28, 2010 at 1:31 am

Dude! Thanks so much for posting the working example of this scene changer. This is exactly what I was looking for for my game. I am trying to translate this exact idea into Flash Builder right now, and this blog has been a big help. It’s been a big help with a lot of other AS3 stuff too! Keep it up.

Michael Williams January 28, 2010 at 5:28 am

Hey crila,

Glad to know this is useful :) Let me know if you make any changes to it — I think there are a lot of things that could be done to make this more suitable for Flash.

crila January 29, 2010 at 8:00 pm

Using the example I skinned and changed up this little game in a day.

http://crila.net/gameTest/gameTest.html

I just reskinned it and made the asteroids appear in different sizes. The code is so well layed out! Good way to learn about game scenes. Also, seeing this layout has helped me see how I should change my game Robot Soldiers of Fortune.

Michael Williams January 31, 2010 at 5:06 am

Nice! Very well presented.

I love your site’s pre-loader — the link to the devblog doesn’t work though :(

crila February 1, 2010 at 4:23 pm

Yeah I had to take my devblog down! I was getting sooo much spam on it. It was blowing up my email inbox. I’ll be starting it up again in the near future though.

Mushyrulez February 1, 2010 at 6:00 pm

:O Use wordpress, it has a built-in spam detector, Akismet, I think…

.-= Mushyrulez´s last blog: Mushyrulez: …g’night… =-.

Michael Williams February 2, 2010 at 7:13 pm

Akismet is pretty good, but FFG introduced me to WP-SpamFree, which is just fantastic. I used to get dozens of spams per day, but now I get, like, one a month, even though my traffic has gone up considerably.

Bret Moretti February 8, 2010 at 9:22 pm

Great tutorial I almost have it working for me but I have a question.

I have the Scene System implemented and when I launch Main I have Main change the scene to MenuScene which works great.

Now my question is: Once I am in MenuScene how can I go to other scenes?
If I have a button (in MenuScene) to change to say “Level1″, do I have to import GameSceneManager from within my MenuScene Class again
and do this again in Menuscene but for Level1:

var levelone:Level1 = new Level1();
GameSceneManager.changeScene( levelone );

If not How do I go to other scenes?

Any help would be greatly appreciated.

Bret Moretti February 9, 2010 at 2:58 am

Hi again,

Just to update I got a few screens working now but what I am doing is for every scene I have, I have to make sure to import whatever scene classes in that I want to be able to have access to from a particular scene. For instance if I want to switch to Level1 scene from MenuScene then in the MenuScene class I have to import the Level1 class then do:

var levelone:Level1 = new Level1();
GameSceneManager.changeScene( levelone );

Is there a better way to do this? How can make all my scene classes aware of each other so I can call anyone of them at anytime from any scene?

Michael Williams February 9, 2010 at 8:39 pm

Hey Bret,

Great question. (I really need to update this post at some point, erk.)

Here’s what I’m trying at the moment. I have two classes: GameSceneManager (actually, I’m calling this ScreenManager), and FlowManager.

GameSceneManager is pretty much the same as I laid out above. It doesn’t need to change between different games.

FlowManager is new, and it changes entirely depending on what game I’m using it in. As you might guess, it controls the flow of the different screens. It does this by listening to events.

My document class contains an instance of FlowManager called flowManager, and when the game’s loaded, it calls flowManager.startFromScratch().

The startFromScratch() function just loads whatever screen I want to start with — so in your case, it’d probably do this:

public function startFromScratch():void
{
    //...somewhere I have defined menuScene as an instance of MenuScreen
    GameSceneManager.changeScene( menuScene );
}

Actually, that’s not all. It also listens for an event:

public function startFromScratch():void
{
    GameSceneManager.changeScene( menuScene );
    menuScreen.addEventListener( FlowEvent.START_GAME, onMenuStartGame );
}

So as you can see I also have a custom event class called FlowEvent. When the player clicks the Start button, I make the MenuScreen call:

dispatchEvent( new FlowEvent( FlowEvent.START_GAME ) );

Phew, getting complicated! Now, FlowManager has an event handler for this:

public function onMenuStartGame( flowEvent:FlowEvent ):void
{
    menuScene.removeEventListener( FlowEvent.START_GAME, onMenuStartGame );
    GameSceneManager.changeScene( playScene );
    playScene.addEventListener( FlowEvent.GAME_OVER, onPlayGameOver );
}

…and then I’ll have another handler to switch the play scene for the game over scene, and so on.

It looks overly complex but it actually makes it pretty simple to change things around if I need to. More importantly, it means I don’t have to make all the classes refer to all the other classes, which would get messy.

What do you think?

Bret Moretti February 9, 2010 at 9:27 pm

Thanks for writing back Michael ! I like your solution.

I actually got mine to do something very similar. But probably not as pretty.

Here is what I did:

in GameSceneManager I made a new function.

public static function getClass(someclass:String):void{
 var ClassReference:Class = getDefinitionByName(someclass) as Class;
}

Which lets me add new classes willy nilly whenever I want by passing it a string name of the class I want.

Then in say MenuScene if I want to call Level1 I can do that with a button event listener: like:

function LeveloneClick(event:MouseEvent):void {
        //call level one
GameSceneManager.getClass("Level1");
        var levelone:Level1 = new Level1();
        GameSceneManager.changeScene( levelone );

…and I can do that as long as I have a class file with that name in my class path.

I don’t have a document class per se because I am writing this all on the command line in VIM!

But what what I do have is a preloader that when it finishes loading it loads class equivalent to Main (just named differently)
and Main calls GameSceneManager.changeScene( menuScene ); as it imports GameSceneManger.

So the first thing anyone sees after the preloader is the menuScene that now can call any level I want.

I am not sure what the drawbacks would be for me doing it this way but if I find out if there are any I will do it your way!

I have another question now though which is:
If we keep loading new scenes or switching back to scenes from within our game, every time calling GameSceneManager.changeScene( menuScene ); , what happens to the other scenes? Are they still sitting there in memory and eventually going to cause us problems? I see that when we change scenes the old scene appears to be replaced on screen with the new one. So what is actually happening to the old ones?

In our Event Listeners should we be cleaning the old scenes some how by calling unload for the old scenes (providing we had some code there to dump everything)?

If I can get this bare bones skeleton finished It should make life much easier for making games:)

Thanks again for your help and insight.

Bret Moretti February 10, 2010 at 6:30 pm

Michael, it’s me again…been working on this again today…first I must apologize this is only my second week working with AS3 so please for give me if I am a little off in my questions:)

Anyway, I have been trying to figure out what happens to the scenes and I noticed that when things declared like var foo:myMovieClip = new myMovieClip; and added via addChild to one scene are not available in another scene unless I re-declare it and add it again the new scene. This is case even if the class is imported in GameSceneManager. So in other words the class for myMovieClip is available to all new scenes but the object has to be declared and added again in each scene.

1) does that mean myMovieClip is gone from memory once the scene is switched?
2)Is there a better way to make one object created in a scene known to all other scenes? sort of like re-parenting but between scenes?

Thanks for putting up with my noobie questions!

Michael Williams February 13, 2010 at 1:56 am

Hey Bret,

You’re writing this with VIM? That’s… crazy! :P

Your method is fine, though two points:

  1. I don’t think you need to do GameSceneManager.getClass("Level1"); — the code you have after that should be enough.
  2. You are restricting yourself — all the code regarding level changes now needs to be in the individual classes. But that’s not a huge deal, necessarily.

As long as you clean everything up in your scenes’ unload() methods (remove all event listeners, things like that), then the individual scenes will eventually be garbage collected. (Check out my Avoider Game Tutorial for more; I explain garbage collection in Part 12.) The unload() function gets called automatically when you call GameSceneManager.changeScene().

About your “foo” example: yeah, foo will only be accessible by the class in which you declared it unless you pass it to another class. If you just re-declare it in another scene, then it will create a whole new one (and the old one will still exist). Again, check out Part 12 of my avoider game tutorial for more info on memory :) Or alternatively, take a look at this: AS3 Resource Management, by Grant Skinner

Michael Williams March 29, 2010 at 3:40 pm

Hey all,

Allen Chou has just posted a really great tutorial explaining his scene system. I’m very impressed, and will likely switch to it. It’s got similarities to Riverman Media’s, as well.

Check it out here.

Bret Moretti March 29, 2010 at 4:28 pm

Thanks for the update Michael…going to read now!

Kustrle August 20, 2010 at 3:51 pm

I’ve just got little problem. Seems that if I switch from scene 1 (menu) to scene 2 (game) or vice-versa lot of times memory gets filled up. What things I should unload in “unload” function? There is no event listeners added to stage, all of them are just added to scene object (I just type addEventListener(…)), so they should be removed when their parent is removed? And since just as event listeners all objects are childs of scene object they should be removed too when parent is removed? I’m probably missing something.

Michael Williams August 21, 2010 at 12:52 am

Further update: Check out this tutorial by Thomas Griffin (aka Psyflash): Handling Screen Architecture: The Painless Way!

@Kustrle: If you’ve got any public or private vars in the class, it’s worth setting them to null, too. Yeah, from the sound of it, your event listeners should be removed… Odd. Check out this article by Daniel Sidhion: Understanding Garbage Collection in AS3.

Leave a Comment

Writing code? Write <pre> at the start and </pre> at the end to keep it looking neat.

Anti-Spam Protection by WP-SpamFree

Previous post:

Next post: