How to Use the Flash IDE as a Level Editor

by Michael James Williams on June 1, 2009 · 38 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 :)

{ 38 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

Brandon March 17, 2010 at 12:47 am

I am having a problem placing the level in another frame. I want to do this because I am making a game menu (frame 1 = menu and frame 2 = level on main timeline). When I try to do so it comes up with “TypeError: Error #1009: Cannot access a property or method of a null object reference. at Level$iinit()”. It does work when I put the level in the first frame though. Why? Here is my code:

package 
{
    import flash.display.*;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    import flash.events.Event;

public class Level extends MovieClip
{
    public function Level(){

    var childIndex:int = 0;
    while ( childIndex &lt; currentLevel.numChildren )
    {
        if ( currentLevel.getChildAt( childIndex ) is Platform )
        {
            if ( currentLevel.hero.hitTestObject( currentLevel.getChildAt( childIndex ) ) )
            {
                trace("collide");
            }
        }
        childIndex++;
    }
}

}

}

Michael Williams March 20, 2010 at 12:03 pm

Hey Brandon,

I avoid using timeline code for anything other than preloaders as it just causes too many problems. To fix your error #1009, start by following my debugging guide to narrow down the line and situation that’s causing it.

Michael Williams March 20, 2010 at 12:04 pm

Also, is Level your document class, or is it the class for one specific movie clip?

Brandon March 20, 2010 at 3:59 pm

Level is my document class. Thanks for the help, I’ll remake it without the timeline.

Michael Williams March 20, 2010 at 4:04 pm

Oh! In that case, try:

    public function Level(){

gotoAndStop( 2 );    //this line is new

var childIndex:int = 0;
while ( childIndex &lt; currentLevel.numChildren )
{
if ( currentLevel.getChildAt( childIndex ) is Platform )
{
if ( currentLevel.hero.hitTestObject( currentLevel.getChildAt( childIndex ) ) )
{
trace("collide");
}
}
childIndex++;
}

Hmm, actually, I suspect that won’t work. You’ll probably need to add a listener for Event.RENDER. (I think RENDER is the right one.) Try it out, see if it works. See, I think the problem’s because the objects don’t really exist until Flash loads that particular frame — so you need to force it to go to that frame.

But yeah, single-frame documents are generally easier to deal with :)

Brandon March 20, 2010 at 4:39 pm

I figured out a solution! I attached the Level class to the 2nd frame instead of the stage and voila. I don’t understand it, but I’m going to make games like this from now on.

Michael Williams March 20, 2010 at 4:46 pm

Sorted! :)

cpucpu April 10, 2010 at 8:11 am

Do you know what would be great? being capable to transform FlashIDE into a true level editor, how? well it basically has almost everything a level editor features:
-rule
-objects adding and removing
-info panel for every individually selected object
-importing objects

Exept one thing, exporiting for xml…
Do you know if there is someway to script this? like a component or something so. Imagine a script that could read the object type, x, y, width, height proepties of all visual objects into the IDE canvas and write taht onto an xml file. So that we could them load and position that objects read from an xml. So we could forget of the boilerplate code for checking if is a platfrom, or what type of enemy is, blabla…

That would be optimal at least from the SDK dev side.

Michael Williams April 13, 2010 at 4:38 pm

Yes yes yes :) I agree completely.

Ahh exporting for XML was actually going to be the next part of this tutorial, if I ever got round to writing it ;) It makes so much sense.

In vaguely-related news, have you seen Ogmo Editor?

cpucpu April 17, 2010 at 6:31 pm

Looks interesting above all ’cause is the first flash oriented level editor i see, i may try it at some point, although with level editing i think more in free objects than grids or tiles, it depends on the type of game you are working on of course. Anyway , now i am trying the flash IDE to xml level aproach, has gone very well so far.

Michael Williams April 23, 2010 at 1:06 pm

Awesome. Got anything to show?

cpucpu May 1, 2010 at 8:13 pm

I wish, have some projects on hand, but in very early development stages. You are the one who should show us something, how long ago did you you write about blitting…

Michael Williams May 7, 2010 at 8:03 pm

Oh man, I’ve been told!

OK, yes, I do have something, just not posted on my blog yet: Part 1, Part 2.

James Hagborg August 20, 2010 at 3:14 pm

Thanks so much!!!!

I’ve been making so many pages of code for everything in classes. I had about twelve .as files and a game with a million glitches and this is so much simpler.

Michael Williams August 21, 2010 at 12:53 am

Oh.. thanks, James! I’m glad you found it useful :)

Nacho October 28, 2010 at 5:11 am

This was an awesome tutorial! Thank you!
However… I feel like if you build a pretty large level in this way, the while loops will consume a lot of computer resources…
Perhaps I’m exagerating, but isn’t there any way to optimize this a bit more?

Jóhann April 15, 2011 at 10:39 pm

Hi I was just wondering… where do you get the:

 p_level; 

from?

And how come you’re declaring the variables inside the function if the other function is going to use them? Just wondering because it doesn’t seem to work for me :(
And last question: Where do I put the function, do I just drop them in the main function? or?
Thanks in advance

Bigfoot November 26, 2011 at 8:54 pm

I was able to implement the first part of the code into the Avoider Game AS file I’ve been working with, but once I get up to 14 enemies my frame rate starts really lagging… if I get up to 20 enemies on screen at once I might hit single digit frame rates! Is my computer just too weak, or is my code doing something retarded?
See, I put this in, and commented out the old code that used to deal with enemy movement and collisions

var childIndex:int = 0;
var currentChild:DisplayObject;
while ( childIndex < this.numChildren )
{
    currentChild = this.getChildAt( childIndex );
    if ( currentChild is Enemy )
    {
        trace( "Enemy!", this.numChildren, childIndex );
        ( currentChild as Enemy ).MoveABit();
        if ( PixelPerfectCollisionDetection.isColliding( avatar, currentChild, this, true ) )
        {
            gameTimer.stop();
            avatarHasBeenHit = true;
        }
        if ( currentChild.y > 425 )
        {
            removeChild( currentChild );
            army.splice( currentChild, 1 );
        }
    }
    childIndex++;
}

It works… but I can literally run circles around my enemys (when using my mouse :) )

Michael James Williams December 1, 2011 at 8:36 pm

Hey Bigfoot, long time no see! I suspect it’s to do with the PixelPerfectCollisionDetection, but not 100% sure. Try sticking in some trace() statements that trace the current time before and after certain bits of code, and seeing which parts take the longest to run.

Brandon Reed September 30, 2012 at 5:07 pm

Hello Mike

I had a question about this. I was attempting to put the information for my IDE inside my classes that i add to the stage (such as my Hero and Enemies). I was doing this to provide a self contained way to add enemies (since mines will appear at random of all types) and the code for each could be nestled inside of each of the classes.

So how would i add the functionality of the Flash IDE to the Sub Class and not the main class themselves. IF there is a possible way?

pure raspberry ketones dr oz recommended June 16, 2013 at 10:19 am

Aw, this was a really nice post. Spending some time and actual effort to
generate a very good article… but what can I say… I procrastinate a whole lot and never seem to get anything done.

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: