Tutorial: Make a Rhythm Game in AS3 – Part 4


Written By MrSun at 8:04 am - Saturday, January 24th, 2009
Categories: Flash

Step 4: Programming the Arrows: Part 2

Ok, now that we’ve gotten the arrows onto the stage, we can actually make them move up the stage and hitTest them with the receptors. We’re going to do all of this by making a base arrow class.

The first step to creating such a thing is to create a new Actionscript (.as) file. Immediately save it as “Arrow.as” and place the following code into it:

package{
	import flash.display.MovieClip;
	import flash.events.*;
	public class Arrow extends MovieClip{
		public function Arrow(){
			 
		}
	}
}

This is the basic skeleton for any AS3 class. But, before we add any more code to it, we have to set it as the base class for all of the arrows. Right click on any of the arrow symbols in the library and click on “Properties…”. Under the “Class:” field, there should be another field called “Base Class:”. Right now, it’s set as flash.display.MovieClip. Set it now as “Arrow”. Do this for all four of the arrows. Now, we can add code to the class:

package{
	import flash.display.MovieClip;
	import flash.events.*;
	public class Arrow extends MovieClip{
		private var _root:Object;//we'll use this to refer to main timeline
		public var arrowCode:int;//the key that needs to be pressed
		public function Arrow(){
			 this.addEventListener(Event.ADDED, beginClass);
			 this.addEventListener(Event.ENTER_FRAME, eFrame);
		}
		private function beginClass(e:Event):void{
			_root = MovieClip(root); //typing _root is much easier than MovieClip(root)
			
			stage.addEventListener(KeyboardEvent.KEY_DOWN, checkKeys);
		}
		private function eFrame(e:Event):void{
			this.y -= _root.arrowSpeed;//move it up the stage
			
			//if game is over or it's off the stage, destroy it
			if(_root.gameOver || this.y < -60){
				destroyThis();
			}
		}
		private function checkKeys(e:KeyboardEvent):void{
			//checking if a certain key is down and it's touching the receptor
			if(e.keyCode == arrowCode && this.hitTestObject(_root.mcReceptor)){
				destroyThis();//remove it from stage
			}
		}
		private function destroyThis():void{
			this.removeEventListener(Event.ENTER_FRAME, eFrame);
			stage.removeEventListener(KeyboardEvent.KEY_DOWN, checkKeys);
			_root.removeChild(this);
		}
	}
}

Now, in order for this code to work, we have to add some stuff to the makeLvl function. Just change it to this:

function makeLvl(e:Event):void{
	//code here will create the level
	if(sTime < sTempo){
		//if the required time hasn't reached the limit
		//then update the time
		sTime ++;
	} else {
		//if the time has reached the limit
		//then reset the time
		sTime = 0;
		//if an actual arrow can be made
		if(lvlArrayAll[lvlCurrent][sArrow] != 0){
			var currentArrow:MovieClip; //this will hold the current arrow
			if(lvlArrayAll[lvlCurrent][sArrow] == 1){
				//place a left arrow onto the stage
				currentArrow = new arrowLeft();
				//set the _x value of the arrow so that it is in the
				//right place to touch the receptor
				currentArrow.x = 135;
				//set the arrow's y coordinate off of the stage
				//so that the user can't see it when it appears
				currentArrow.y = 500;
				//setting the key that needs to be pressed
				currentArrow.arrowCode = 37;
				addChild(currentArrow);//add it to stage
			} else if(lvlArrayAll[lvlCurrent][sArrow] == 2){
				//place an up arrow onto the stage
				currentArrow = new arrowUp();
				currentArrow.x = 205;
				currentArrow.y = 500;
				currentArrow.arrowCode = 38;
				addChild(currentArrow);
			} else if(lvlArrayAll[lvlCurrent][sArrow] == 3){
				//place a down arrow onto the stage
				currentArrow = new arrowDown();
				currentArrow.x = 275;
				currentArrow.y = 500;
				currentArrow.arrowCode = 40;
				addChild(currentArrow);
			} else if(lvlArrayAll[lvlCurrent][sArrow] == 4){
				//place a right arrow onto the stage
				currentArrow = new arrowRight();
				currentArrow.x = 345;
				currentArrow.y = 500;
				currentArrow.arrowCode = 39;
				addChild(currentArrow);
			}
		}
		//get the next arrow if it the song isn't finished
		if(sArrow < lvlArrayAll[lvlCurrent].length){
			sArrow ++;
		} else {
			//if the song is finished, then reset the game
			//of course, we don't have the code for that yet
			//so we're just going to go back to the first frame
			gotoAndPlay(1);
			gameIsOver = true;
		}
	}
}

Now, if you test the game now, there's going to be a problem. The game will reset before all of the arrows even reach the receptor. There are two ways that I can think of to fix this. The first option is to count all of the arrow instances on stage and when it's 0, then end the game. The second, which I prefer, is to just add a certain amount of "0"'s to the end of the array each time the game begins. The second option is what I'm going to do. In the beginCode() function, add the following code.

//make the level array longer
lvlArrayAll[lvlCurrent].push(0,0,0,0,0);

Now, the game should be working out pretty well. I'm pretty proud of our progress this lesson, so I'm going to end it now. We've finished the basic gameplay of the game. Next lesson, we will make a menu system where the player can choose which games to play. It'll be great.

Final Product

Source Files (zipped)

4 Comments

Aku:

Sorry for that post.
I was using AS 2.0 not 3.0. so it didn’t work.
Sorry.


nick:

I can’t get this to work for some reason.
Whenever I try to destroy the objects I keep getting this output error:

TypeError: Error #2007: Parameter hitTestObject must be non-null.
at flash.display::DisplayObject/_hitTest()
at flash.display::DisplayObject/hitTestObject()
at Arrow/checkKeys()

That being said I did tamper with the code a little to allow for five objects instead of the four arrows.


Sighouf:

Hey great tutorial so far.
Im having some problem with the receptor i always get this error
when i hit the keys.

TypeError: Error #2007: Parameter hitTestObject must be non-null.
at flash.display::DisplayObject/_hitTest()
at flash.display::DisplayObject/hitTestObject()
at Arrow/checkKeys()

Does anyone have an idea what im doing wrong?


Usaka:

after saving the code as a as. file, now i went to properties and typed “arrow” by the catagory “Base Class” but it says it cannot be changed. does typing it in “Class” differ from typing it in the “base class”?


«
»