Separating a Level’s Layout from its Appearance

by Michael James Williams on June 8, 2009 · 9 comments

in Articles,Flash IDE

This is a follow-up post to How to Use the Flash IDE as a Level Editor. If you haven’t read that yet, check it out first!

Now that our code can detect the layout of symbols we’ve positioned using the IDE, we can separate levels’ layout from their appearance.

Why bother? Here’s a few reasons:

  • We’ve designed level layouts, but not the artwork to go with them.
  • There may be different people handling the art and the level design.
  • We might want to keep the same game but alter the appearance for different websites

Plus, once we’ve put the work in, other benefits will appear; I’ll show you some of these in this post.

First, let’s look at using this to experiment with different “themes”.

Themed Levels

Going back to the platformer example, suppose that game actually splits levels up into different themes — like Zones in Sonic or Worlds in Mario. We’ve got a forest theme, with lots of grass and wood, a winter theme, with lots of snow and ice, and so on.

Now imagine we’ve designed a level layout and we can’t decide which theme would fit it best. We also need to consider how it slots into the game as a whole; we don’t want a really difficult level to come right at the start.

For the sake of this post I’ll assume we already designed this level using the forest theme’s graphics, and are just now having second thoughts. So here’s how it looks in the IDE:

screenshot

The simplest thing to do would be to right-click every single object, select Swap Symbol, and choose the correct symbol from the library.

screenshot

But this is tedious, and there’s a good chance we’ll make mistakes. It will be much simpler to automate this with code — and thanks to the loadLevelFromSymbol() function we wrote in the first part of this tutorial, we can do just that.

It just needs a little tweaking. First, we need to let the function create a new MovieClip based on the symbols from the IDE, rather than using the MovieClip that we pass it:

?View Code ACTIONSCRIPT3
public function createLevelFromMovieClip( p_level:MovieClip ):MovieClip 
{
	var levelToReturn:MovieClip = new MovieClip();
	var newObject:MovieClip;
 
	_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 );
		newObject = null;
 
		if ( currentChild is BasePlatform )
		{
			if ( currentChild is WoodPlatform )
			{
				newObject = new WoodPlatform();
				newObject.x = currentChild.x;
				newObject.y = currentChild.y;
				//set other properties here...
				levelToReturn.addChild( newObject );
			}
			else if ( currentChild is GrassPlatform )
			{
				newObject = new GrassPlatform();
				newObject.x = currentChild.x;
				newObject.y = currentChild.y
				//set other properties here...
				levelToReturn.addChild( newObject );
			}
			if ( newObject != null )
			{
				_platformsArray.push( newObject );
			}
		}
		if ( currentChild is BaseEnemy )
		{
			//do the same thing with the enemy
		}
 
		childIndex++;
	}
 
	return levelToReturn;
}

That’s quite long, and could certainly be optimised, but you get the idea. The code that calls this function would now use the MovieClip that’s returned, rather than the one that was passed. This new MovieClip contains brand new GrassPlatforms, WoodPlatforms, and so on, with the same properties as in the IDE. All the arrays have been changed to hold these new objects, so they work as before.

Now this lets us introduce a new argument which holds the theme:

?View Code ACTIONSCRIPT3
public function createLevelFromMovieClip( p_level:MovieClip, p_theme:String ):MovieClip

…which in turn requires some changes to the while-loop:

?View Code ACTIONSCRIPT3
while ( childIndex < _currentLevel.numChildren )
{
	currentChild = _currentLevel.getChildAt( childIndex );
	newObject = null;
 
	if ( currentChild is BasePlatform )
	{
		if ( currentChild is WoodPlatform )
		{
			if ( p_theme == "Forest" )
			{
				newObject = new WoodPlatform();
				newObject.x = currentChild.x;
				newObject.y = currentChild.y;
				//set other properties here...
				levelToReturn.addChild( newObject );
			}
			else if ( p_theme == "Winter" )
			{
				newObject = new IcePlatform();
				newObject.x = currentChild.x;
				newObject.y = currentChild.y;
				//set other properties here...
				levelToReturn.addChild( newObject );
			}
			//check other themes...
		}
		else if ( currentChild is GrassPlatform )
		{
			//same thing here:
			//depending on theme, create either GrassPlatform or SnowPlatform
		}
		if ( newObject != null )
		{
			_platformsArray.push( newObject );
		}
	}
	if ( currentChild is BaseEnemy )
	{
		//do the same thing with the enemy
	}
 
	childIndex++;
}

So now we can switch from forest levels to winter levels on the fly, but we can’t do the other way round. Just as in the first post in this series, we could fix this by using messy chains of if statements:

?View Code ACTIONSCRIPT3
if ( currentChild is BasePlatform )
{
	if ( ( currentChild is WoodPlatform ) || ( currentChild is IcePlatform ) )    //will get long!
	{
		if ( p_theme == "Forest" )
		{
			newObject = new WoodPlatform();
			//etc

…and again we can avoid this by using inheritance. All we need to do is make both WoodPlatform and IcePlatform extend a common class — let’s say BridgePlatform — which in turn extends BasePlatform, and we can simplify the above:

?View Code ACTIONSCRIPT3
if ( currentChild is BasePlatform )
{
	if ( currentChild is BridgePlatform )
	{
		if ( p_theme == "Forest" )
		{
			newObject = new WoodPlatform();
			//etc

(Naturally we would also make GrassPlatform and SnowPlatform extend a new class GroundPlatform which in turn extends BasePlatform.)

Now a level designed with one theme can be given another theme at run-time.

Bonus Benefits

If we create new symbols called BridgePlatform, GroundPlatform, and so on, we can even just use those to design our levels:

screenshot

Actually, if you’re willing to write the code you could even make your function take a level like this:

screenshot

…and automatically replace that long GroundPlatform with two regular (themed) ones, positioned side by side. Perhaps it could even choose different styles of GroundPlatform (within the same theme, of course!) to go next to each other, so that the ground isn’t just the same tile repeated over and over again.

Something to bear in mind here: the function I wrote above won’t do anything with any objects it doesn’t recognise. This can be beneficial; for example, I can write notes about certain layout decisions I made in order to share them with other people working on the game, or just so that I don’t forget them.

screenshot

Since the function doesn’t have a if ( currentObject is SimpleText ) check, nothing will be done with this annotation and the player won’t see it. Admittedly, this could have been done before simply by adding all such text to a guide layer.

However, doing it this way gives us the opportunity to show the annotations inside the game — perhaps in debug mode, or an unlockable “developer’s commentary”. We’d just have to alter the above code so that it added the text objects to the new level MovieClip if (and only if) this were true.

This is Getting Silly

OK, I’ll admit I may be getting a bit too wrapped up in the technology here, and not looking at whether this would actually be useful in a game. The truth is, if a simple spritesheet swap is all that separates your forest levels from your winter levels, your game is probably quite dull. At the very least, you’d want your ice blocks to make the character slide around uncontrollably, like in every game ever, right? And speaking at a higher level, perhaps you’d want the forest levels to feel very claustrophobic, with obstacles all over the place, while winter levels were vast open spaces with a lot of bottomless pits.

Perhaps platformers are the wrong sort of game to use this with. A game like Breakout makes more sense, since all those tiles would be a pain to place with a text editor (in Flash we can just turn on Snap to Grid) and the appearance of the tiles shouldn’t affect the core gameplay (as evidenced by the million clones).

We can also use this approach for games where layout is not used to position actual in-game items. For example, suppose we were making a point and click game with several rooms. Naturally we’d need each room to know which other rooms surrounded it — the ballroom is north of the dining room, which is east of the drawing room, etc. This gets more complicated if you allow for different sizes of room.

We could just write code like:

ballroom.southRoom = diningRoom;
diningRoom.northRoom = ballroom;
//etc

But why not just create a bunch of movie clip symbols, one for each room, and lay them out in the IDE as you imagine them in the game world? A little code can work out how all the rooms connect, and you can reposition and resize them however you like. These symbols will never actually be seen in-game, but who cares? Remember, you have access to all the properties of a standard MovieClip, so that includes x, y, scaleX, scaleY, height, width, and many more besides. In fact, in a later post I’ll show you how to add properties of your own that can be edited within the IDE.

Having said all that, I do think there are two big reasons this is useful for all types of game (including platformers).

First, for prototyping. If you’re trying a whole bunch of different art styles out (pixel, photo, cartoon, …) it’s very handy to be able to switch between them by altering a few lines of code.

Second, you might not actually have access to the art assets. If you’re working with an artist, you wouldn’t expect them to finish all the art before you started on the code and level design. You might not even hire an artist until you have a demo up and running, in which case you can send them your programmer art spritesheet and say “like this, only good”. Again in a later post, I’ll show you how to keep your art assets, your code, and your level design all in separate files so that everyone involved can work on their part separately.

Click here to subscribe for free so that you don’t miss it :)

{ 9 comments… read them below or add one }

Mushyrulez June 8, 2009 at 6:24 am

O_o This may be hard to use in an avoiding game, but for other games, this could be useful.

Gonna write a platformer tutorial soon?

Michael Williams June 8, 2009 at 11:31 am

Actually, I think you could use this in an avoider game. Check out the conversation between Fred and I in the comments of Turn Your Avoider Game into a Shoot-’Em-Up. He wanted to be able to define what time various enemies appeared; you could do this by creating a tall thin movie clip and dragging enemies onto it — your code would then interpret distance along the y-axis as time before the enemy appears.

Platformer games… I would love to write such a tutorial but don’t have the time. I wrote more about that in the comments of the About page actually. Mr Sun and Emanuele both have platformer tutorials, though :)

DanielSidhion June 8, 2009 at 5:45 pm

Great MJW! I loved this tutorial. You are getting close to what I saw on scripts of game emulators. They worked with many weapons, armors, spells, and just putting things as BaseWeapon, BaseArmor, BaseSpell made everything easier.
I’m waiting for the next tutorial to start thinking on the structure of the engine of my next game.
About the shape modelling I was searching: I found a good site (http://www.flashandmath.com/basic/drawpathCS4/index.html) with some cool scripts. I will use them on my starting code.

I wanna talk to you about some colision detection methods I found on the web, and about some other interesting things. When and where can we meet? Maybe at night on FGL? Thank you.

Michael Williams June 8, 2009 at 5:57 pm

Thanks Daniel! I’m glad you found something for your modelling, that sounds like it’ll be a cool game.
I’ll try to pop on FGL later tonight :)

Rasmus Wriedt Larsen (Snurre) June 8, 2009 at 8:58 pm

Yay, another great tutorial Michael! I really like where this is going :)

and thanks for the link Daniel. This looks very nice.

default0 Once Again ;) January 22, 2011 at 9:51 pm

Hey Mic,

It’s been some time until I’ve posted or read here, but I hope you still remind me.

I have to make some suggestions on how to optimize the code much further.

First, when initializing levels (making the theme look neat) you could either use frames and tell the platforms to go to the theme’s frame (ie

someplatform.gotoAndStop(gameTheme);

) instead of creating a new one (which obviously takes a bunch of performance for level initialization), or better yet, draw Bitmaps on the stage, based on indexes for the themes. If you don’t want to get confused with what number is what theme you could make an enumeration like this:

package
{
    public class Themes
    {
        public static const ForestTheme:int = 0;
        public static const IceTheme:int = 1;
    }
}

And then have all the theme images in a sprite sheet and use BitmapData operations to draw the right one based on theme.

Also, make dedicated arrays to speed the main loop up, for example:

public var PlatformArray:Array;

Then, as you initialize, get the class of the object with

someobject is SomeType

and push it to the correct array. Then loop over these arrays with foreach instead of checking what class they are every time (which again eats up a bunch of performance).

This way you can gain lots of performance, and keep messiness out if you f.e. want an enemy to interact only with certain platforms (you would have to check if the object you’re dealing with actually is a platform every time the enemy has to be updated).

Well, I still get the point of the tutorial, and it’s a nice one to get the general idea of using Flash IDE the right way ;)

So, all in all, nice tutorial, but there certainly can be made lots of optimizations :)

Best regards

Nick May 29, 2011 at 2:10 pm

Hello, I’ve been looking for a way to edit the variables of an object dragged onto the stage from Flash’s IDE, and my search brought me here.

“In fact, in a later post I’ll show you how to add properties of your own that can be edited within the IDE.”

I think this is exactly what I’m looking for, and so I’ve been poking around your blog, but I haven’t been able to find it. I’d appreciate it if you could provide a followup link/explanation :)

Michael James Williams May 30, 2011 at 12:42 pm

Hey Nick,

I never got round to writing that post, I’m afraid. It’s something I’ve been exploring again recently, and I might go into it in a post for Activetuts+ soon.

In the meantime, I recommend that you follow this tutorial. It’ll introduce you to the concept of creating “parameters” for Flash components, which is basically what I was going to use in my post :)

Nick May 31, 2011 at 3:57 am

Ah, that’s perfect! I can’t believe how it easy it was, and that it took me this long to do it.

I ran into a problem with using flash as a level editor though. Since I’m making a platformer, the levels tend to be really wide, and flash professional CS5 seems to have a limit to the stage size at 2880 pixels. There’s a point where when dragging objects further to the right, that the bottom scroll bar doesn’t expand to accommodate the new object. I can still drag objects there, and see them from within the game, but I’m unable to look further past that point from the flash IDE.

Is there anyway around this limit? Or am I forced to program a workaround, such as making chunks of level and moving them when the level starts?

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: