How to Use the Flash IDE as a Level Editor

by Michael Williams on June 1, 2009 · 17 comments

in Articles, Flash IDE

A lot of tutorials talk about designing levels in code, using XML or an array of arrays, or just setting x and y properties of various objects. This approach works, but it feels primitive. I mean, I spent £500 on a piece of professional design software, and you’re telling me I should lay out my levels with a text editor?

No thanks, Chuckles!

Fortunately, it’s really not that difficult to use the Flash IDE (that is, the actual Flash CS3/CS4 program) to design levels for games, and in fact using it in this way makes it easier for us to separate level design, art assets, and code. It even lets us create in-game level editors without much effort at all!

This article is an introduction to using Flash as a level editor, explaining how we can grab information about the symbols on the stage. In the next part we’ll take this further.

The Most Basic (and Common) Method

There’s a very simple method people have been using since AS2 was popular.

screenshot

In the above screenshot, I’ve got a number of Platform movie clips, each with an instance name of platform1, platform2, and so on. Same deal with the enemies. The player’s character has an instance name of hero.

All of these are either placed directly onto the stage, or is inside a movie clip that is linked to an AS file which contains all the code to power the engine. (The details aren’t important.)

We can then write collision detection code like this:

?View Code ACTIONSCRIPT3
if ( ( hero.hitTestObject( platform1 ) ) || ( hero.hitTestObject( platform2 ) ) )
{
	//deal with this collision
}

…where “dealing with the collision” involves checking which side of the platform the hero is hitting and stopping it falling if necessary.

Obviously that if statement is going to get very long! There are other problems, too; when we add a new platform we have to add a new clause to the if statement; removing platforms is similarly messy.

We need a way to loop through all the platforms, without having to manually add new platforms to the loop.

Automatic Loops

In AS2 it was common to write code like this:

?View Code ACTIONSCRIPT2
for (i = 1; i < 10; i++) {
   var currPlatform = this["platform" + i];
   //check currPlatform for collision with hero
   //and deal with it
}

this["platform" + i] gets a reference to the variable whose name is in the square brackets — so this["platform" + 1] is equal to platform1. As long as all our platforms have instance names that follow this pattern, the above code will deal with looping through them without any further changes on our part.

Well… except we have to change that i < 10 if we have more than 10 items. And we have to make sure that no two platforms have the same name. And, OK, it might be a bit of a pain to name every single platform.

We can do better. In AS3, every MovieClip (indeed, every DisplayObjectContainer) has a function, getChildAt() that returns each display object that has been “addChild()-ed” to them. This includes all the library symbols that you drag on to the clip at design time. If we use this with the numChildren property we can easily loop through every single object in the level:

?View Code ACTIONSCRIPT3
var childIndex:int = 0;
while ( childIndex < currentLevel.numChildren )
{
	currentLevel.getChildAt( childIndex ).alpha = 0.5;
	childIndex++;
}

(Here I’m assuming that we’ve made a new movie clip library symbol, dragged a bunch of objects into it, and have created a new instance of it called currentLevel.)

That’s just a simple demo that shows how to create such a loop, and sets the alpha of every item in the level to 50% to prove it works. Note: this entire article assumes that you have turned on Automatically declare stage instances in the Publish Settings. This may interfere with the rest of your code; we’ll look at getting around this in a follow-up article.

Thanks to OOP, we don’t need to give every platform an instance name. Instead, we can just give the platform symbol a class in the library — let’s call it Platform, for simplicity’s sake. In our code, we can use the is keyword to see whether the child of the level that we are currently looking at is an instance of the Platform class:

?View Code ACTIONSCRIPT3
var childIndex:int = 0;
while ( childIndex < currentLevel.numChildren )
{
	if ( currentLevel.getChildAt( childIndex ) is Platform )
	{
		if ( hero.hitTestObject( currentLevel.getChildAt( childIndex ) ) )
		{
			//deal with this collision
		}
	}
	childIndex++;
}

That code could be run every tick.

Of course, we can simplify this:

?View Code ACTIONSCRIPT3
var childIndex:int = 0;
var currentChild:DisplayObject;
while ( childIndex < currentLevel.numChildren )
{
	currentChild = currentLevel.getChildAt( childIndex );
	if ( currentChild is Platform )
	{
		if ( hero.hitTestObject( currentChild ) )
		{
			//deal with this collision
		}
	}
	childIndex++;
}

…and support other classes of object:

?View Code ACTIONSCRIPT3
var childIndex:int = 0;
var currentChild:DisplayObject;
while ( childIndex < currentLevel.numChildren )
{
	currentChild = currentLevel.getChildAt( childIndex );
	if ( currentChild is Platform )
	{
		if ( hero.hitTestObject( currentChild ) )
		{
			//deal with this collision
		}
	}
	else if ( currentChild is Enemy )
	{
		if ( hero.hitTestObject( currentChild ) )
		{
			//deal with this collision
		}
	}
	childIndex++;
}

In fact, we could just move most of the logic in here. For example, how about the enemy’s movement?

?View Code ACTIONSCRIPT3
else if ( currentChild is Enemy )
{
	currentChild.moveABit();
	if ( hero.hitTestObject( currentChild ) )
	{
		//deal with this collision
	}
}

Looks good, but unfortunately currentChild.moveABit() will cause an error. That’s because all Flash knows about currentChild is that it’s a DisplayObject — and DisplayObjects don’t have a function called moveABit(). That’s OK; we can use casting:

?View Code ACTIONSCRIPT3
else if ( currentChild is Enemy )
{
	(currentChild as Enemy).moveABit();
	if ( hero.hitTestObject( currentChild ) )
	{
		//deal with this collision
	}
}

(The as keyword just tells Flash, “treat this object as an instance of this class”.)

Sub-Classes of Objects

Suppose you wanted to create a new type of platform:

screenshot

We’d set the class of this new platform to WoodPlatform, and change the old platform’s class to GrassPlatform to be consistent.

The obvious thing to do next is change our code like so:

?View Code ACTIONSCRIPT3
currentChild = currentLevel.getChildAt( childIndex );
if ( ( currentChild is GrassPlatform ) || ( currentChild is WoodPlatform ) )
{
	if ( hero.hitTestObject( currentChild ) )
	{
		//deal with this collision
	}
}

…but this leaves us with a similar problem to before; whenever we want to add a new class of platform, we’ll have to edit our code.

No need to worry, though, because we’ve got inheritance. Just create a new AS file like so:

?View Code ACTIONSCRIPT3
package  
{
	import flash.display.MovieClip;
	public class BasePlatform extends MovieClip
	{
		public function BasePlatform() 
		{
 
		}
	}
}

Now, whenever you create a new platform symbol, just set BasePlatform as its base class, like so:

screenshot

If you don’t create the WoodPlatform class yourself, Flash will do it for you — and it’ll make it extend BasePlatform, too. This means that any instance of the WoodPlatform class counts as being an instance of the BasePlatform class, as far as the is keyword is concerned, so if you do this for all your platform symbols, you can simplify the troublesome code:

?View Code ACTIONSCRIPT3
currentChild = currentLevel.getChildAt( childIndex );
if ( currentChild is BasePlatform )
{
	if ( hero.hitTestObject( currentChild ) )
	{
		//deal with this collision
	}
}

Of course, you can do the same thing with enemies, and any other group of objects that share a common class.

Right now we’re looping through all the on-stage objects once per tick, and dealing with them as we come to them. But what happens if we want to check, for example, whether any bullet is colliding with any enemy? The normal method would be to use a nested loop — but the only way we can do that here is to loop through all the on-stage objects again.

We need to split everything into separate arrays. Let’s look at how to do that.

Arrays of Classes

I’d like to have a few arrays; one containing references to all the platforms, one for all the enemies, one for all the bullets, and so on. That way, I could organise my tick() function like so:

?View Code ACTIONSCRIPT3
public function tick():void 
{
	for each ( var platform:BasePlatform in _platformsArray )
	{
		if ( hero.hitTestObject( platform ) )
		{
			//deal with collision
		}
	}
 
	for each ( var enemy:BaseEnemy in _enemiesArray )
	{
		enemy.moveABit();
		if ( hero.hitTestObject( enemy ) )
		{
			//deal with collision
		}
	}
 
	for each ( var bullet:BaseBullet in _bulletsArray )
	{
		bullet.moveABit();
		for each ( var enemy:BaseEnemy in _enemiesArray )
		{
			if ( bullet.hitTestObject( enemy ) )
			{
				//deal with collision
			}
		}
	}
}

(That code could be optimised, but you get the idea.)

Not only does this allow shorter loops, and remove the need to cast elements of an array every time, it also lets us remove an object from the stage without destroying our means of access to it.

Getting the objects into the arrays is really simple. At the start of the level, we just call a function createLevelFromMovieClip() that works like this:

?View Code ACTIONSCRIPT3
public function createLevelFromMovieClip( p_level:MovieClip ):void 
{
	_currentLevel = p_level;
 
	_enemiesArray = new Array();
	_platformsArray = new Array();
	_bulletsArray = new Array();
 
	var childIndex:int = 0;
	var currentChild:DisplayObject;
	while ( childIndex < _currentLevel.numChildren )
	{
		currentChild = _currentLevel.getChildAt( childIndex );
 
		if ( currentChild is BasePlatform )
		{
			_platformsArray.push( currentChild );
		}
		if ( currentChild is BaseEnemy )
		{
			_enemiesArray.push( currentChild );
		}
 
		childIndex++;
	}
}

You could also make one master array of all the items inside the movie clip, then filter() it down to separate the platforms from the enemies.

Wrapping Up

We’ve separated the code from the layout to a great extent, and now we can use Flash’s toolbox to add, move and resize level objects without having to worry about changing the engine to deal with them.

The next step is separating the layout from the art, coping with multiple levels and objects with more properties than just position (like HP, for instance), and looking at the possibilities for in-game level editing.

Click here to read on :)

{ 17 comments… read them below or add one }

Ramon Fritsch June 1, 2009 at 5:08 am

great! in as3, everything is more easy. :)

tomdeaap June 1, 2009 at 11:21 am

You are an absolute genius … :p

Michael Williams June 1, 2009 at 2:42 pm

Thanks guys! Also thanks to Snurre for pointing out I forgot to put childIndex++ in my while loops. Whoops…

samuvagyok June 1, 2009 at 3:48 pm

It’s good to see how much work are in your articles. cheers!

RedRail June 1, 2009 at 8:26 pm

Good article. I hope this is a begining of a mini series, because I’m really looking forward to the next step!

Michael Williams June 2, 2009 at 12:10 pm

Cheers :) And yep, I’ll be writing another post on this topic soon — probably this weekend.

Michael Williams June 7, 2009 at 3:48 pm

So it seems I’m in the top Google results for ["No thanks, Chuckles!"]. That’s pretty funny. I feel I should mention that I came across the phrase in my favourite web comic about talking dinosaurs.

mitomane June 15, 2009 at 3:18 pm

great explanation.

Michael Williams June 15, 2009 at 3:37 pm

Cheers mitomane :)

Ecky Putrady September 13, 2009 at 4:46 am

I’m planning to make a level editor for my box2D based platformer game. And after reading your article, I feel like, “why should I make my own level editor if the flash IDE itself can be used as a level editor?” This really is a great Idea. Genius! Thanks for sharing ;)

Michael Williams September 13, 2009 at 4:58 pm

Thanks Ecky — that’s exactly how I feel! Glad you liked it :) Funnily enough I’ve been working with Box2D myself recently, so I’ll be writing about that soon too.

buagaga December 3, 2009 at 4:53 pm

Great article! I necessarily use it in my new game. Thanks a lot.

Michael Williams December 4, 2009 at 12:31 pm

Cheers, buagaga.

Jerome S January 12, 2010 at 2:38 am

Where does currentLevel come from? I understand you can drag an item to the stage and export it for actionscript, but how do you make everything you drag onto the stage a child of that one object?

Michael Williams January 12, 2010 at 10:41 pm

Oh, good point, I didn’t explain that very clearly. The idea is, you create a new movie clip in the library, edit it, drag in a bunch of objects (platforms, etc), then export it for actionscript and create an instance called currentLevel.

Cheers for your comment, I’ve updated the tutorial to clear that up.

Quakeboy January 26, 2010 at 6:54 am

What should I do to think like you… I’m jealous you are a genius !

Quakeboy´s last blog: Simflex Image Gallery – Full Free Flex Image Gallery

Michael Williams January 26, 2010 at 7:46 am

Ahaha thanks man. Best comment ever :P

Leave a Comment

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

CommentLuv Enabled

Anti-Spam Protection by WP-SpamFree

Previous post:

Next post: