AS3 Avoider Game Tutorial, Part 10: Multiple Levels

by Michael Williams on March 10, 2009 · 72 comments

in Avoider Game Base, Tutorial

We’ve got a lot of the features necessary for a game to be considered a game, but we’re missing a key ingredient: progression. At the minute, the game doesn’t get any harder, so there’s no real sense of achievement for surviving the game for a long time, since it all comes down to luck and stamina. It’s also the case that after a few seconds of play, you’ve seen everything the game has to show you — not just from a graphics point of view, but from a gameplay/experience point of view, too.

Therefore, in this part of my AS3 and Flash CS3 conversion of Frozen Haddock’s avoider game tutorial, we’ll add new levels the player can reach.

Click the preview image below to check out how this will play:

screenshot

If you’ve not been following the tutorial, grab the zip file of the game so far here and extract it somewhere. Otherwise, copy the files you’ve been working on so far to a new folder, as usual. Open the FLA file, and let’s get started.

What Are Levels?

Before we decide to add levels to our game, let’s look at the different ways other game developers have incorporated levels.

In Dodge, you start off pitted against a few yellow enemies.

screenshot

When you destroy all enemies, you’re given a quick breather and a chance to trade points for health before moving on to the next level. Later levels increase the number of enemies on-screen, and also introduce more kinds of enemies, like this blue one:

screenshot

Amorphous+ does not have the same sort of level structure. You effectively choose what level to play at the start, picking the number of enemies to fight or the rate at which the difficulty increases, or specifying a specific type of enemy to practise against. Within the game, you play the level through to the end (or until you die), and the longer you survive, the more vicious the enemies that spawn:

screenshot

The level’s background is picked at random when you start playing:

screenshot

Finally, Four Second Frenzy is different from all the above. Like the WarioWare series of games, it uses “microgames” with completely different objectives, rather than simply adding new elements to a single core game.

screenshot

The microgames do all tie in to a single control structure and set of lives, though.

So, clearly, there are a lot of different meanings to this idea of a “level”. A change in level might simply mean a visual change, but more often it’ll mean a change in the difficulty, the types of enemies, the scoring conditions, or even the entire ruleset of the game! You need to decide what levelling up means in your game.

What I’ll Do

Based on what I’ve said in previous parts of this tutorial, it may seem natural to make one class per level, with each class extending AvoiderGame, and use events to switch between them. So, we might have classes named AvoiderGameLevelOne, AvoiderGameLevelTwo, etc., and let each one fire off a “NavigationEvent.NEXT_LEVEL” when appropriate. Presumably then the document class would listen for this event, and when it heard it, it would run “playScreen = new AvoiderGameLevelTwo()” (or whichever level was appropriate), and pass through all the information such as score and time to this new playScreen instance.

That structure would work, and it does seem to follow what we’ve already done with the different screens in the game. It would also be particularly useful for a game like the aforementioned Four Second Frenzy, whose levels were made by different people. The trouble is, it’s very restrictive for any game that wants to keep a single set of rules.

For one thing, we’d be restricted to a finite set of levels. If the player finishes AvoiderGameLevelTen and there’s no AvoiderGameLevelEleven, then that’s it, game over. This is fine for some games, especially if a story is involved, but for an arcade-style game that we want to keep getting more challenging rather than just ending, it’s hardly ideal.

Consider Tetris. At the end of each level, all that happens is the blocks fall faster, and the score earned for making a line increases. Some versions change the background colour too. If we were going to use one class per level, then we’d lose all the blocks that had already fallen each time we created a new level. If we wanted to keep them, we’d have to pass all the information about where they were up to the document class, and then let the document class pass that information back down into the new level. And we’d still have to stop increasing the falling speed and points earned per line once we ran out of level classes.

I’m going to base my level structure on Tetris, with a new level meaning a change in background and a greater number of enemies appearing per tick. Therefore, I don’t want to use the class-per-level approach. But what can we do instead?

When you think about it, all the AvoiderGame class contains is a set of rules, the mechanics of the game. When you press “up”, AvoiderGame checks its list of rules and sees that this means the avatar should be moved up a few pixels. Every time a new enemy is created, AvoiderGame knows to add some points to the score. But we could easily alter the exact number of pixels the avatar should move, or the exact number of points to add to the score, without changing the underlying structure of the rules.

So, we can create new levels simply by changing these values depending on what level the player is on. We could use if statements, like so:

?View Code ACTIONSCRIPT3
if ( currentLevel == 1 )
{
	gameScore.addToValue( 10 );
}
else if ( currentLevel == 2 )
{
	gameScore.addToValue( 15 );
}
else if ( currentLevel == 3 )
{
	gameScore.addToValue( 22 );
}

…but then we end up with bits of level-specific code dotted all around the class, with no easy way to find or edit it all at once. Close, very close, but not quite good enough.

The best solution I know of is to store all the level-specific information in a separate place from the rules, and then have the AvoiderGame class request the values it needs for the current level. Read on to find just how to do that.

The LevelData Class

Let’s start by making a striking and obvious visual change between levels: the background.

Start by opening up the PlayScreen symbol in the library (remember this is linked to the AvoiderGame class file). At the minute, the background is just sort of drawn on to the PlayScreen itself. If we want to be able to change it using code, we’ll have to make it a symbol of some kind. Select all of it, being careful not to select the clock and score (you can select multiple objects by holding shift while clicking them):

screenshot

To make this into a symbol (in this case, we’ll make it a movie clip), click Modify > Convert To Symbol. Call it BackgroundContainer — I’ll explain why in a minute — and export it for actionscript with the same name.

Because we have a preloader, we need to uncheck the Export in first frame box, and add the movie clip to the AssetHolder movie clip. For more information on doing that, check out Part 8. From now on, I’m not going to mention it, so be sure you remember to do it for each symbol. You can of course leave it, then do it for a bunch of symbols at once, perhaps when you finish the game.

Anyway, edit the BackgroundContainer if you’re not doing so already, and again select all of the background elements and convert them to a new symbol of type movie clip. I’m calling mine BlueBackground but of course this might not be appropriate for whatever you’ve drawn, so name it accordingly. Export it for ActionScript with the same name, too.

Now, go back to editing PlayScreen, and give the BackgroundContainer movie clip an instance name of backgroundContainer. It’ll probably be in front of the score and clock, so right-click it, select Arrange, and click Send to Back:

screenshot

So now the PlayScreen contains a movie clip of class BackgroundContainer, which in turn contains another movie clip that is our BlueBackground.

Great. Now right-click the BlueBackground in the library, and select Duplicate. Call it RedBackground, export it for ActionScript, and start editing it. Here’s what mine looks like:

screenshot

No surprises there. Save it and run it to make sure everything’s still working with the blue background.

Now it’s time to make the class that’ll contain the level-specific information. Create a new AS file, and save it as LevelData.as in the Classes directory. Here’s the base code:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
10
package
{
	public class LevelData
	{
		public function LevelData()
		{
 
		}
	}
}

Note that it’s not extending anything — it doesn’t need to. We want this to contain all the data relevant to the level, and at the minute that’s just the background colour, so add a class-level variable called backgroundImage:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
10
11
12
package
{
	public class LevelData
	{
		public var backgroundImage:String;
 
		public function LevelData()
		{
 
		}
	}
}

How do we link the level number to the background, though? Like this:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package
{
	public class LevelData
	{
		public var backgroundImage:String;
 
		public function LevelData( levelNumber:Number )
		{
			if ( levelNumber == 1 )
			{
				backgroundImage = "blue";
			}
			else if ( levelNumber == 2 )
			{
				backgroundImage = "red";
			}
		}
	}
}

So when we create a new instance of this LevelData class, we’ll pass through the number of the level that we’re currently on, and it’ll set its backgroundImage variable to the colour corresponding to that level’s background. We can then obtain this variable from within AvoiderGame. Let’s do that now.

Save this class file, and go back to AvoiderGame.as. Create a new class-level variable to hold the current level’s data:

?View Code ACTIONSCRIPT3
27
public var currentLevelData:LevelData;

In the constructor function, instantiate this object like so:

?View Code ACTIONSCRIPT3
29
30
31
public function AvoiderGame() 
{
	currentLevelData = new LevelData( 1 );

Now, currentLevelData.backgroundImage will contain the text “blue”. Feel free to trace() it to check it’s working. What we’re going to do now is put the correct background into the, well, background:

?View Code ACTIONSCRIPT3
29
30
31
32
33
34
35
36
37
38
39
public function AvoiderGame() 
{
	currentLevelData = new LevelData( 1 );
	if ( currentLevelData.backgroundImage == "blue" )
	{
		backgroundContainer.addChild( new BlueBackground() );
	}
	else if ( currentLevelData.backgroundImage == "red" )
	{
		backgroundContainer.addChild( new RedBackground() );
	}

What this is doing is addChild-ing the correct background image to the backgroundContainer clip, not to the play screen. Since the background container is already right at the back, this means it’ll stay behind the score, the clock, the avatar and the enemies. If we just wrote addChild( new BlueBackground() ) we’d have to manually move it to the back. This solution is kind of like painting over a wall with the background image we want to display; we’re not actually removing the image that’s already there, just sticking something new on top of it. Obviously this is inefficient.

You might be wondering why we don’t just place an instance of BlueBackground on the play screen, with an instance name of backgroundImage, and then write, backgroundImage = new RedBackground() as we need to. The issue is that since BlueBackground and RedBackground are different classes, we can’t just swap them like that, even though they are both just sub-classes of MovieClips. We can get around this by unchecking the Automatically declare stage instances option in the Publish Settings, and this is not very complicated, but it’d require adding quite a lot of code so I don’t want to go into it now.

Anyway, if you save and run it, you’ll see that the game has a blue background. Great, but that doesn’t exactly prove anything. So change the 1 in this line:

?View Code ACTIONSCRIPT3
currentLevelData = new LevelData( 1 );

to a 2:

?View Code ACTIONSCRIPT3
currentLevelData = new LevelData( 2 );

Save it and run it again:

screenshot

Awesome.

Level Up!

That basically shows that we can skip to a specific level, but how about actually progressing to a new level from within the game?

First we need to decide what a player needs to do to get to the next level. One idea I’ve seen a couple of people suggest in the comments and by email is placing a target on-screen that the avatar has to reach to get to the next level. That’s a cool idea, but I’m going to do something simpler for now; I’m just going to put the player in a new level when they reach a certain score.

Change that 2 back to a 1 so that the player starts on the first level. Now, the best place to check the player’s score is in the onTick() function, so move to that part of the code. I’m going to add the check right at the end of the function, so that everything else can happen first:

?View Code ACTIONSCRIPT3
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
	if ( avatarHasBeenHit )
	{
		bgmSoundChannel.stop();
		dispatchEvent( new AvatarEvent( AvatarEvent.DEAD ) );
	}
 
	if ( gameScore.currentValue >= 150 )
	{
		currentLevelData = new LevelData( 2 );
		if ( currentLevelData.backgroundImage == "blue" )
		{
			backgroundContainer.addChild( new BlueBackground() );
		}
		else if ( currentLevelData.backgroundImage == "red" )
		{
			backgroundContainer.addChild( new RedBackground() );
		}
	}
}

Lines 183-194 are the new ones. Well, I say that, but lines 186-193 are copied from above, so let’s move them to a new function, setBackgroundImage():

?View Code ACTIONSCRIPT3
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
	if ( avatarHasBeenHit )
	{
		bgmSoundChannel.stop();
		dispatchEvent( new AvatarEvent( AvatarEvent.DEAD ) );
	}
 
	if ( gameScore.currentValue >= 150 )
	{
		currentLevelData = new LevelData( 2 );
		setBackgroundImage();
	}
}
 
public function setBackgroundImage():void
{
	if ( currentLevelData.backgroundImage == "blue" )
	{
		backgroundContainer.addChild( new BlueBackground() );
	}
	else if ( currentLevelData.backgroundImage == "red" )
	{
		backgroundContainer.addChild( new RedBackground() );
	}
}

That’s neater. Go back and replace those lines with a call to setBackgroundImage() in the constructor function, too.

If you save and run this, you’ll find that although it does change the background after you get enough points, it runs awfully slowly. The reason for this is the if statement that we’re using:

?View Code ACTIONSCRIPT3
if ( gameScore.currentValue >= 150 )

Obviously that’ll still be true if the score is 160, 170, or over 9000. So every tick after you get 150 points for the first time, it’s going to run; 40 times a second, a new background will be created and painted over the old one. No wonder it gets a bit laggy.

How can we fix this? Well, here’s my solution. First, add a new variable, pointsToReachNextLevel, to the LevelData class, and set it up like so:

?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
package
{
	public class LevelData
	{
		public var backgroundImage:String;
		public var pointsToReachNextLevel:Number;
 
		public function LevelData( levelNumber:Number )
		{
			if ( levelNumber == 1 )
			{
				backgroundImage = "blue";
				pointsToReachNextLevel = 150;
			}
			else if ( levelNumber == 2 )
			{
				backgroundImage = "red";
				pointsToReachNextLevel = 9999999;
			}
		}
	}
}

(I’ve temporarily set it to some ridiculously huge number to reach level three since we haven’t got there yet.) Now, back in AvoiderGame, just set that troublesome if statement to use this new variable:

?View Code ACTIONSCRIPT3
176
177
178
179
180
if ( gameScore.currentValue >= currentLevelData.pointsToReachNextLevel )
{
	currentLevelData = new LevelData( 2 );
	setBackgroundImage();
}

Test it out, and it should work fine. Excellent! Now how about increasing the rate at which enemies appear on level two? It’s really simple; you might want to try it out yourself before reading on.

All you need to do is add a new variable to the LevelData class (and set it up):

?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
package
{
	public class LevelData
	{
		public var backgroundImage:String;
		public var pointsToReachNextLevel:Number;
		public var enemySpawnRate:Number;
 
		public function LevelData( levelNumber:Number )
		{
			if ( levelNumber == 1 )
			{
				backgroundImage = "blue";
				pointsToReachNextLevel = 150;
				enemySpawnRate = 0.05;
			}
			else if ( levelNumber == 2 )
			{
				backgroundImage = "red";
				pointsToReachNextLevel = 9999999;
				enemySpawnRate = 0.1;
			}
		}
	}
}

…and then use this in AvoiderGame (see line 126 below):

?View Code ACTIONSCRIPT3
126
127
128
129
130
131
132
133
134
if ( Math.random() < currentLevelData.enemySpawnRate )
{
	var randomX:Number = Math.random() * 400;
	var newEnemy:Enemy = new Enemy( randomX, -15 );
	army.push( newEnemy );
	addChild( newEnemy );
	gameScore.addToValue( 10 );
	sfxSoundChannel = enemyAppearSound.play();
}

Infinite Levels

I said above that one of the disadvantages of using one class per level was that we would be restricted to a finite set of levels. So far, we’ve only got two, which is hardly worth boasting about. Let’s add a couple more. Start by adding the level-specific data to the LevelData class:

?View Code ACTIONSCRIPT3
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
public function LevelData( levelNumber:Number )
{
	if ( levelNumber == 1 )
	{
		backgroundImage = "blue";
		pointsToReachNextLevel = 150;
		enemySpawnRate = 0.05;
	}
	else if ( levelNumber == 2 )
	{
		backgroundImage = "red";
		pointsToReachNextLevel = 350;
		enemySpawnRate = 0.1;
	}
	else if ( levelNumber == 3 )
	{
		backgroundImage = "blue";
		pointsToReachNextLevel = 600;
		enemySpawnRate = 0.13;
	}
	else if ( levelNumber == 4 )
	{
		backgroundImage = "red";
		pointsToReachNextLevel = 9999999;
		enemySpawnRate = 0.15;
	}
}

Since I’ve only got two backgrounds, I’m just alternating between them. Naturally you can make more and use those, as long as you alter the setBackgroundImage() function accordingly.

We’ve got a problem, though. Check out that if statement again:

?View Code ACTIONSCRIPT3
176
177
178
179
180
if ( gameScore.currentValue >= currentLevelData.pointsToReachNextLevel )
{
	currentLevelData = new LevelData( 2 );
	setBackgroundImage();
}

Line 178 above shows us that we’re just going to keep loading level 2 over and over again. We need to move it to the next level, i.e. we need to run something like, currentLevelData = new LevelData( currentLevelNumber + 1 );. We could create a new variable within AvoiderGame called currentLevelNumber, but I think we might as well store this in LevelData as well. Just alter it like so:

?View Code ACTIONSCRIPT3
5
6
7
8
9
10
11
12
public var backgroundImage:String;
public var pointsToReachNextLevel:Number;
public var enemySpawnRate:Number;
public var levelNum:Number;
 
public function LevelData( levelNumber:Number )
{
	levelNum = levelNumber;

I’d call the variable levelNumber, but that’s what I’ve called the variable I’m passing into the constructor function, so levelNum will have to do. Now in AvoiderGame we just have to refer to this value:

?View Code ACTIONSCRIPT3
176
177
178
179
180
if ( gameScore.currentValue >= currentLevelData.pointsToReachNextLevel )
{
	currentLevelData = new LevelData( currentLevelData.levelNum + 1 );
	setBackgroundImage();
}

Save it and run it, and you’ll see we now have four levels (but if you manage to get ten million points you’ll get a lot of errors). That’s fine and all, but why not shoot for infinitely many levels?

All we have to do for that is decide on a general rule for setting these values. If you’ve done “nth term” sequences in algebra class you’ll understand this. Take a look how I’ve done it for the numeric values:

?View Code ACTIONSCRIPT3
31
32
33
34
35
36
37
38
39
40
41
42
else if ( levelNumber == 4 )
{
	backgroundImage = "red";
	pointsToReachNextLevel = 770;
	enemySpawnRate = 0.15;
}
else
{
	backgroundImage = "blue";
	pointsToReachNextLevel = levelNumber * 200;
	enemySpawnRate = 0.6 - ( 2 / levelNumber );
}

(Don’t forget to change the points to reach level 5 to be something a bit more manageable!)

If you work the maths out, you can see that when the player gets to level five, they need 1000 points to reach the next level, and the enemies spawn at a rate of 0.2 per tick. Level six requires 1200 points to pass, and the enemies spawn at a rate of roughly 0.27 per tick. You can continue this onwards forever, though the game does get pretty slow once a lot of enemies have been spawned (we’ll talk about fixing this problem in Part 12).

We’re nearly done, but there’s one thing that still bugs me — the background stays blue from level five onwards. Of course, we could use Math.random() to pick the colour of the background after level four, but I’d much rather have it alternate between blue and red.

To achieve this, we can use the modulo function, which I’ve not introduced yet. Modulo gets you the remainder after a division. One divided by two is zero remainder one, so one modulo two is one. Two divided by two is one remainder zero, so two modulo two is zero. Three divided by two is one remainder one, so three modulo two is one. You get the idea; basically levelNumber modulo two will alternate between one and two; levelNumber modulo five would count from one to five and then start again. If you’d like to read lots and lots about the modulo operation, check out Wikipedia’s article.

Anyway, it’s simple to add. Modulo is represented in code by the percentage sign, %, so we can use it like so:

?View Code ACTIONSCRIPT3
37
38
39
40
41
42
43
44
45
46
47
48
49
else
{
	if ( levelNumber % 2 == 1 )
	{
		backgroundImage = "blue";
	}
	else
	{
		backgroundImage = "red";
	}
	pointsToReachNextLevel = levelNumber * 200;
	enemySpawnRate = 0.5 - ( 2 / levelNumber );
}

Easy.

Challenges

This opens up a huge range of challenges you can attempt. For starters, how about displaying the current level number and the number of points required to reach the next level? You could also alter the speed of the enemies or the avatar as the player gets further through the game. And if I tell you that all movie clips (and thus all classes extending movie clips) have .scaleX and .scaleY properties that alters the width and height of the object (so that setting it to 1 is normal size, 2 is twice as big as normal, and 0.5 is half as big as normal), could you alter the size of the enemies and avatar according to the level?

If you’ve added different kinds of enemies to your game, you might want to have multiple spawn rates, one for each kind, so that you can let the nastier enemies appear more and more often as the player gets further through the game (like in Amorphous+). If you haven’t done this, you could combine this idea with the above tip regarding scaleX and scaleY, and use different sizes of the standard enemy instead of different types.

How about splash screens between levels? You can use gameTimer.stop() to effectively pause the game, and then pop up a simple button for the player to click to move on to the next level using the “GameOverText” method from Part 3. You could even create cutscene movie clips to go in-between certain levels.

Bonus levels could be cool, too. For example, every fifth level make coins appear instead of enemies, and hitting them adds to your score instead of killing the player.

You could also alter the conditions for moving to the next level. Perhaps base them on time rather than score, or on reaching a different point in the level. Maybe you could make a level select screen, or have a cheat code that players can enter to skip a level.

If you have any other ideas, please stick them in the comments so that other people can try them!

Wrapping up

Hey, look at that, we’re all done and we didn’t import or extend anything, or add any event listeners! That’s pretty unusual.

As always, you can download a zip with all the files relating to this part of the tutorial here.

In the next part, we’ll look at creating and reloading savegames.

{ 1 trackback }

AS3: Base Tutorial, Part 10 | Avoider Game . com
March 31, 2009 at 12:22 am

{ 71 comments… read them below or add one }

Michael Williams September 26, 2009 at 7:34 pm

Oh, when I talked about implementation I meant “are you going to change your game to work this way?”

Good tip with including separate files, but actually you don’t need to switch to frame-based code to do that. If you have a class called StandardFunctions in your /classes/ directory, and it contains a static function called getRotationToPoint(), you can just write:

import StandardFunctions;

…and then you can use it like this: StandardFunctions.getRotationToPoint()! :D

FlashN00b September 27, 2009 at 10:11 am

great hint! Thanks :)

FlashTrainee October 6, 2009 at 5:39 pm

Hello,

first of all, thanks for this amazing tutorials! I am a real newbie, and I’m getting really frustrated trying to understand how ActionScript works. I’m getting there really slowly but at least I can see the potential of such a useful tool. Now, I’m trying to do something that is apparently not too hard, but that I can’t really figure it out.

I would like to increase the speed of the enemies every level more. I tried to work on the levelData.as using different solutions involving the Enemy.as file as well, but nothing happenened, I mean at the moment I’m not even getting any error from flash, it just doesn’t work :( that’s the last try:

package 
{
    import flash.display.MovieClip
    public class LevelData extends Enemy
    {
        //public var backgroundImage:String;
        public var pointsToReachNextLevel:Number;
        public var enemySpawnRate:Number;
        public var speedIncrease:Number;
        public var levelNum:Number;

    public function LevelData(levelNumber:Number)
    {   
        super(x, y);
        levelNum = levelNumber;

        if (levelNumber == 1)
        {
            backgroundImage = "blue";
            pointsToReachNextLevel = 10;
            enemySpawnRate = 0.10;
            speedIncrease = ySpeed + 1;
        }
        else if (levelNumber == 2)
        {
            backgroundImage = "green";
            pointsToReachNextLevel = 50;
            enemySpawnRate = 0.15;
            speedIncrease = ySpeed + 2;
        }
        else if (levelNumber == 3)
        {
            backgroundImage = "blue";
            pointsToReachNextLevel = 150;
            enemySpawnRate = 0.25;
            speedIncrease = ySpeed + 3;
        }
        else if (levelNumber == 4)
        {
            backgroundImage = "green";
            pointsToReachNextLevel = 999;
            enemySpawnRate = 0.35;
            speedIncrease = ySpeed + 4;
        }

    }
}

}

Can you give me an hint on how to proceed?

Thank you again very much!

Michael Williams October 7, 2009 at 5:38 pm

Hey FlashTrainee, thanks for the kind words :)

That’s an interesting idea, making the LevelData extend Enemy. I see what you were trying to do there, and I think it’d be neat to see that taken further. However, just to keep things simple for myself and for other readers, I’m going to talk as though you hadn’t made any changes from the tutorial yet, i.e. as though LevelData did not extend Enemy.

In this case, I would suggest creating a public var enemySpeed:Number inside LevelData, much as you have. Then, in each if statement, I’d set that to a new number, like so:

            if (levelNumber == 1)
            {
                backgroundImage = "blue";
                pointsToReachNextLevel = 10;
                enemySpawnRate = 0.10;
                enemySpeed = 1;
            }
            else if (levelNumber == 2)
            {
                backgroundImage = "green";
                pointsToReachNextLevel = 50;
                enemySpawnRate = 0.15;
                enemySpeed = 1.2;
            }
            else if (levelNumber == 3)
            {
                backgroundImage = "blue";
                pointsToReachNextLevel = 150;
                enemySpawnRate = 0.25;
                enemySpeed = 1.35;
            }

… and so on.

My idea is to make the enemy’s speed be multiplied by this enemySpeed value. So, if on level one the enemies move at 3 pixels per second, then on level two they will move at (3 * 1.2) pixels per second, and so on. The best place to do this is in the moveABit() function inside Enemy.as. Instead of

enemy.x = enemy.x + xSpeed;

…you would need something like:

enemy.x = enemy.x + (xSpeed * enemySpeed);

The tricky part here is, how do you pass enemySpeed to the Enemy?

I’ll just give a hint here — you can do it the same way you pass startX and startY to the enemy when you create it.

Hope that helps :)

DudexD January 17, 2010 at 11:46 am

I’m getting an error that i need help with, iv tryed to figure it out what, and how to fix, but with no luck. I think the mistake is in the Flash file, but not totaly sure… Please help:D

Errors: AvoiderGame.as, Line 204 1120: Acess of undefined property backgroundContainer. AvoiderGame.as, Line 204 1180: Call to a possibly undefined method BlueBackground. AvoiderGame.as, Line 208 1120: Acess of undefined property backgroundContainer.

Codes: 204: backgroundContainer.addChild( new BlueBackground() ); 208: backgroundContainer.addChild( new RedBackground() );

I both got a Blue and a Red background, so i don’t understand why the 1180 error only comes on the blue and not the red one…

Michael Williams January 17, 2010 at 3:43 pm

Hey DudexD,

That is weird that only the blue background causes the #1180. Is the symbol definitely exported for AS with the name BlueBackground?

As for the #1120, it sounds like perhaps your BackgroundContainer on the play screen does not have an instance name of backgroundContainer.

Hope that helps :)

DudexD January 17, 2010 at 5:08 pm

Woops Shouldn’t be working on this early in the morning:D Atleast i got it to work now thanks to your guiding. By the way great tutorials!:D

But there was also something i was wondering, about the Arrow Movement, and it is that if you Hold both Left and Up it should go in both direction at the same time. because as it is now, it is really anoying.

DudexD January 17, 2010 at 6:03 pm

Also, in the LevelData.as i’m having a problem now,

Since i got 4 backgrounds red, blue, yellow and green i’m not totaly sure about how to fix it with the:

else { if ( levelNumber % 2 == 1 ) { backgroundImage = “blue”; } else { backgroundImage = “red”; }

I understand that if i set:

else { backgroundImage = “yellow”; }

after that it wont work. i think maybe i know what to do, but i don’t wanna mess it up, so ill ask instead.

Michael Williams January 17, 2010 at 8:02 pm

Re. diagonal movement: I actually left that out on purpose as a challenge for you :) But Daniel Sidhion has written a tutorial to explain it here, if you’d like more direct instructions.

For the different backgrounds, why don’t you post your idea?

DudexD January 17, 2010 at 8:27 pm

so you want it that way??:D Well i’m not good at explaining tho. so i’m going to test my theories out, then come with feedback:P

DudexD January 17, 2010 at 8:37 pm

HOLY! i did it! it worked! like, all by myself…. well almost :P

Heres my code

if ( levelNumber % 4 == 1 )
                {
                    backgroundImage = "blue";
                }
                else if ( levelNumber % 4 == 2 )
                {
                    backgroundImage = "red";
                }
                else if ( levelNumber % 4 == 3 )
                {
                    backgroundImage = "yellow";
                }
                else
                {
                    backgroundImage = "green";
                }

By the way how do you add those fancy code thingys in comments on this page?

Michael Williams January 17, 2010 at 8:41 pm

Congrats :D

Nice code :)

You can use <pre> and </pre> to make simple code boxes, by the way. I’ve edited your comment to do this.

DudexD January 17, 2010 at 8:45 pm

Thank you :D

Well i better head on to the next tut.

Nik February 11, 2010 at 10:15 am

i tried to put level display on the game overscreen, but none work under AvoiderGame:

public function getFinalLevel():Number
        {
            return gameLevel.levelNum;
        }
       public function getFinalScore():Number
        {
            return gameScore.currentValue;
        }

    public function getFinalClockTime():Number
    {
        return gameClock.currentValue;
    }

under Doc class:

public function onAvatarDeath( avatarEvent:AvatarEvent ):void
        {
            var finalScore:Number = playScreen.getFinalScore();
            var finalClockTime:Number = playScreen.getFinalClockTime();
            var finalLevel:Number = playScreen.getFinalLevel();

    gameOverScreen = new GameOverScreen();
    gameOverScreen.addEventListener( NavigationEvent.RESTART, onRequestRestart );
    gameOverScreen.x = 0;
    gameOverScreen.y = 0;
    gameOverScreen.setFinalScore( finalScore );
    gameOverScreen.setFinalClockTime( finalClockTime );
    gameOverScreen.setFinalLevel( finalLevel );
    addChild( gameOverScreen );

    playScreen = null;
}

GameOverScreen class:

public function setFinalLevel( levelNumber:Number ):void
        {
            finalLevel.text = levelNumber.toString();
        }

where did i miss something? headache……. if you can help, plz thanks

Michael Williams February 13, 2010 at 2:12 am

Hey Nik,

I can’t see anything that you’ve missed :S

Let’s figure out where it’s going wrong. Put a trace() in your GameOverScreen like this:

public function getFinalLevel():Number
        {
            trace( gameLevel.levelNum );
            return gameLevel.levelNum;
        }

Let me know what pops up in the Output panel.

Oh, are you getting any errors, by the way?

Nik February 22, 2010 at 2:58 am

i get error when my avatar die

 
TypeError: Error #1009: Cannot access a property or method of a null object reference.
    at AvoiderGame/getFinalLevel()
    at DocumentClass/onAvatarDeath()
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at AvoiderGame/onTick()
    at flash.utils::Timer/_timerDispatch()
    at flash.utils::Timer/tick()

How to send you my project files? i think easier if you write fix “//note” on the code

thanks

Michael Williams February 22, 2010 at 9:30 pm

Hey Nik,

Kinda busy at the moment, don’t have time to go rooting through other people’s code — sorry!

Check out my debugging guide to find out which line is triggering that error. If you paste the code here (and point out which line it is) I can probably help.

Rick February 27, 2010 at 10:43 am

Hey there! Those tutorial are great, thanks for the help you give to us Michael..

I have a problem too with a features : increase speed of the enemy every level more. I saw the hint you gave to FlashTrainee, but i’m stuck.. can’t figure out what to do.

Can you give me another good hint for that?

Sorry for the “inconvenience”.. hope to see your answer!

Rick March 1, 2010 at 1:31 am

Solved! :D Thank you anyway!

Michael Williams March 20, 2010 at 10:50 am

Good to hear, Rick! How’d you fix it?

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: