Hostingheaderbarlogoj
Join InMotion Hosting for $3.49/mo & get a year on Tuts+ FREE (worth $180). Start today.
Advertisement

How To Select Units in an AS3 Game

by
Gift

Want a free year on Tuts+ (worth $180)? Start an InMotion Hosting plan for $3.49/mo.

In this tutorial, we will draw a selection rectangle with the mouse (as seen in strategy games such as StarCraft and Command and Conquer), and we will also learn how to select units with the rectangle!


Final Result Preview

Let's take a look at the final result we will be working towards:

Click and drag with your mouse to draw a rectangle that will select any soldier that it touches.


Step 1: The Setup

If you are using Flash, create a new ActionScript 3.0 file with the size '550 x 400'. However, if you are not using the Flash IDE and are using another such as FlashDevelop or Flash Builder, this tutorial contains the SWC files so you can use MovieClips from within your IDE of preference. If you are curious on how to import MovieClips with your IDE, check out the Beginner's Guide to FlashDevelop and Beginner's Guide to FDT!

I should also note that I have included the FLA file in case you do not wish to draw any of your own material.


Step 2: Creating the Document Class

Ok, now you may be a little confused if you haven't really worked with classes before. If you wish to learn more about why classes are important in programming, check out this article by kirupa, or this guide to the document class.

Create a new 'ActionScript 3.0 Class' and give it the name 'SelectionDemo'. When the file has been created, save it as 'SelectionDemo.as'. You should save files all the time. I can not stress this enough but the amount of times I have forgot to save work that I have done and lost it all doesn't bear thinking about. So please, do save the files!

If you are using an IDE that generates the code for you when you create the class, you should have most of the code below. However, you must still add the lines that I have highlighted:

package  
{
	
	import flash.display.MovieClip;
	
	public class SelectionDemo extends MovieClip 
   	{

		public function SelectionDemo() 
        	{

		}
	
	}

}

We are not done yet however! If you are using the Flash IDE, navigate to the 'Properties Panel' and set the 'DocumentClass' to 'SelectionDemo'. If you are wondering what that does, it means that when your application/game is run by the Flash Player, this Class will be the Main class that manages the game. Cool, huh?

Exporting the Unit

Run the program; if you get no errors then you should be good to go!


Step 3: Creating the Rectangle

Now we should be ready to make the Rectangle! This part will contain a few functions, that's all. Below is the code for drawing the rectangle:

package  {
	
	// IMPORTING THE CLASSES WE NEED
	import flash.display.MovieClip;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.display.Sprite;
	
	public class SelectionDemo extends MovieClip {
		
		public var selectionRect:Rectangle; // Will hold the data for our rectangle.
		public var selectionSprite:Sprite = new Sprite(); // Making a new Sprite to draw the rectangle.
		
		
		public function SelectionDemo() {
			
			//Adding listeners
			stage.addEventListener(MouseEvent.MOUSE_DOWN, SetStartPoint);
			
		}
		
		
		public function SetStartPoint( me:MouseEvent ):void
		{
			
			selectionRect = new Rectangle( stage.mouseX, stage.mouseY ); // Creating the selection rectangle.
			
		}
		
		
	}
	
}

Now, it's kind of useless having a rectangle that we cannot see, right? Exactly, so let's get started!


Step 4: Drawing the Rectangle

Great, now we must draw the rectangle to the screen using the selectionSprite variable you seen in the last snippet. Why use a sprite, you ask? All Sprites contain a graphics object, which in turn contains a method called drawRect() this allows us to easily draw a rectangle dynamically in AS3.

Below, I have placed the code for drawing the rectangle, with comments:

package  {
	
	// IMPORTING THE CLASSES WE NEED
	import flash.display.MovieClip;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.display.Sprite;
	import flash.events.Event;
	
	public class SelectionDemo extends MovieClip {
		
		public var selectionRect:Rectangle; // Will hold the data for our rectangle.
		public var selectionSprite:Sprite = new Sprite(); // Making a new Sprite to draw the rectangle.
		public var isMouseHeld:Boolean; // Will tell us whether the mouse button is Up/Down
		
		
		public function SelectionDemo() {
			
			//Initializing
			
			isMouseHeld = false; // The mouse is not held yet.
			stage.addChild(selectionSprite); // Adding the selectionSprite to the stage.
			
			stage.addEventListener(MouseEvent.MOUSE_DOWN, SetStartPoint); // Listen for mouse hold.
			stage.addEventListener(MouseEvent.MOUSE_UP, RemoveRectangle); // Listen for mouse release.
			stage.addEventListener(Event.ENTER_FRAME, UpdateGame); // Run this function every frame (24 FPS).
			
		}
		
		
		public function SetStartPoint( me:MouseEvent ):void
		{
			
			selectionRect = new Rectangle( stage.mouseX, stage.mouseY ); // Creating the selection rectangle.
			isMouseHeld = true; // The mouse is now held.
			
		}
		
		
		public function RemoveRectangle( me:MouseEvent ):void
		{
			
			isMouseHeld = false; // The mouse is no longer held.
			
		}
		
		
		public function UpdateGame( e:Event ):void
		{
			
			selectionSprite.graphics.clear(); // Clear the rectangle so it is ready to be drawn again.
			
			if( isMouseHeld )
			{
				selectionRect.width = stage.mouseX - selectionRect.x; // Set the width of the rectangle.
				selectionRect.height = stage.mouseY - selectionRect.y; // Set the height of the rectangle.
				selectionSprite.graphics.lineStyle(3, 0x3B5323, 0.6); // Set the border of the rectangle.
				selectionSprite.graphics.beginFill( 0x458B00, 0.4 ); // Set the fill and transparency of the rectangle.
				selectionSprite.graphics.drawRect( selectionRect.x, selectionRect.y, selectionRect.width, selectionRect.height ); // Draw the rectangle to the stage!
				selectionSprite.graphics.endFill(); // Stop filling the rectangle.
			}
			
		}
		
		
	}
	
}

If you have that code, run your application and watch it work!


Step 5: Draw a Unit

In flash, create a new MovieClip and draw a Unit. In the first frame, just draw a unit; in the second frame, add a green circle under the unit or anything that lets the player know that the unit has been selected. It should look something like this:

Unit MovieClips

I also just drew a quick grassy background on the stage to make it look nice :)


Step 6: Exporting the Unit

Now you have created the MovieClip, right-click the symbol in your Library and select Properties. Check the boxes that say 'Export to ActionScript' and 'Export in Frame 1'. Then, give it the name 'Unit'. Your properties should look something like this:

Exporting the Unit

Note: when you click 'OK', you may get a warning because no such class "Unit" exists yet. If so, click OK and we shall fix this now by making a new class!


Step 7: Creating the Unit Class

Remember before when you exported the Unit MovieClip? This is where we create the class for that MovieClip. So create a new ActionScript class file named 'Unit.as' and place this code within the class:

package  
{
	
	import flash.display.MovieClip;
	
	
	public class Unit extends MovieClip 
	{
		
		public var isActive:Boolean; // Tells us whether the unit is selected or not.
		
		public function Unit() 
		{
		
			isActive = false; // The unit has not been selected yet.
			gotoAndStop(1); // Go to and stay on the first frame ( no selection ring ).
			
		}
		
	}
	
}

Ahead, comrades!


Step 8: Placing the Units

Now it is time to add the Units to the stage and give them a position. Also, we are going to place each Unit in an 'Array'. An array is basically a list which allows us to access the things inside it using an index. A great example of arrays is right at Republic of Code; they've also been explained here in AS3 101: Arrays.

Here is the updated code for 'SelectionDemo.as'. First, we add a new public Array called unitList just after the other variables:

public var selectionRect:Rectangle; // Will hold the data for our rectangle.
public var selectionSprite:Sprite = new Sprite(); // Making a new Sprite to draw the rectangle.
public var isMouseHeld:Boolean; // Will tell us when the mouse is Up/Down
public var unitList:Array; // All the units will be held in here

Then, we update the Main function by placing a function called PlaceUnits(15);. We will create this in a moment.

public function SelectionDemo() {
	
	//Initializing
	isMouseHeld = false; // The mouse is not held yet.
	stage.addChild(selectionSprite); // Adding the selectionSprite to the stage.
	PlaceUnits(15); // Calling a function to place the units on the stage.
	
	//Adding listeners
	stage.addEventListener(MouseEvent.MOUSE_DOWN, SetStartPoint); // Listen for mouse hold.
	stage.addEventListener(MouseEvent.MOUSE_UP, RemoveRectangle); // Listen for mouse release.
	stage.addEventListener(Event.ENTER_FRAME, UpdateGame); // Run this function every frame (24 FPS).

}

Time to make the function! Ok, we will place this function after the UpdateGame(e:Event):void function and what this function will do is add the amount of units you specified in the brackets to the stage. We will also add the units to the list and give them random positions on the stage while making sure they cannot spawn off the stage.

public function PlaceUnits( amount:int ):void
{
	
	unitList = new Array(); //Making a new Array(list) to hold all the Units.
	
	for( var i:int = 0; i < amount; i++ ) // Run whatever is inside the brackets 'amount' times.
	{
		var unit:Unit = new Unit(); // Creating a new unit.
		unit.x = Math.random() * (550 - unit.width); // Setting a random X Position.
		unit.y = Math.random() * (400 - unit.height); // Setting a random Y Position.
		stage.addChild(unit); // Adding the new unit to the stage.
		unitList.push( unit ); // Placing the unit in the Array(list).
	}
			
}

When you run this, you should have 15 units randomly placed. Time to move on and program the unit selection.


Step 9: Z-Sorting!

When you run the game, you will probably see that there is a strange overlap of the units. Let's fix it! This is extremely easy and will only require a small change to the PlaceUnits() function.

Basically, what we need to do is add all the units to an Array (list) and then sort the list based on the Y (vertical position) of the units. The lower the Y property, the further backwards it should be. We will change the PlaceUnits() function to:

public function PlaceUnits( amount:int ):void
{
	
	unitList = new Array(); //Making a new Array(list) to hold all the Units.
	
	for( var i:int = 0; i < amount; i++ ) // Run whatever is inside the brackets 'amount' times.
	{
		var unit:Unit = new Unit(); // Creating a new unit.
		unit.x = Math.random() * (550 - unit.width); // Setting a random X Position.
		unit.y = Math.random() * (400 - unit.height); // Setting a random Y Position.
		unitList.push( unit ); // Placing the unit in the Array(list).
	}
	
	unitList.sortOn("y", Array.NUMERIC); // Sorting the list in order of the 'y' properties!
		
	for( var j:int = 0; j < amount; j++ ) // We will run through this loop again to add the units.
	{
		stage.addChild( unitList[j] ); // This adds the 'sorted' unit to the stage.
	}
			
}

There we have it... no more overlaps!


Step 10: Selecting Units

Now, each frame we will check whether any units have been selected; if they have then we will make their selection ring appear.

Edit the UpdateGame() function to the following:

public function UpdateGame( e:Event ):void
{
			
		selectionSprite.graphics.clear(); // Clear the rectangle so it is ready to be drawn again.
			
		if( isMouseHeld )
		{
			selectionRect.width = stage.mouseX - selectionRect.x; // Set the width of the rectangle.
			selectionRect.height = stage.mouseY - selectionRect.y; // Set the height of the rectangle.
			selectionSprite.graphics.lineStyle(3, 0x3B5323, 0.6); // Set the border of the rectangle.
			selectionSprite.graphics.beginFill( 0x458B00, 0.4 ); // Set the fill and transparency of the rectangle.
			selectionSprite.graphics.drawRect( selectionRect.x, selectionRect.y, selectionRect.width, selectionRect.height ); // Draw the rectangle to the stage!
			selectionSprite.graphics.endFill(); // Stop filling the rectangle.
			CheckForSelection(); // We will check to see if any units have been selected.
		}
			
}

As you can see, we added a function called CheckForSelection(). Let's create that function after the others:

public function CheckForSelection():void
{
		
	for each( var unit:Unit in unitList ) // For every unit that is in the Unit Array(list)...
	{
		
		if( unit.hitTestObject( selectionSprite ) ) // If the selectionSprite is touching the Unit.
		{
			unit.select(); // Make the unit selected.
		}
		else
		{
			unit.deselect(); // De-select the unit.
		}
		
	}
	
}

As you can see in the highlighted lines, the select() and deselect() functions do not exist. Open up 'Unit.as' and let's put them in:

package 
{
	
	import flash.display.MovieClip;
	
	
	public class Unit extends MovieClip 
	{
		
		public var isActive:Boolean; // Tells us whether the unit is selected or not.
		
		public function Unit() 
		{
			
			isActive = false; // The unit has not been selected yet.
			gotoAndStop(1); // Go to and stay on the first frame ( no selection ring ).
			
		}
		
		
		public function select():void
		{
			isActive = true; // The unit is selected.
			gotoAndStop(2); // Show the ring.
		}
		
		
		public function deselect():void
		{
			isActive = false; // The unit is not selected.
			gotoAndStop(1); // Do not show the ring.
		}
		
		
	}
	
}

Run the game and all should be working!


Step 11: Challenges

Now that you have sucessfully completed this tutorial, I now have some challenges for you to follow. Feel free to skip them, but following them will help you learn.

Beginner:

  • Spawn 25 units instead of 15
  • Change the colour and border of the rectangle

Intermediate:

  • All of the above
  • Add a TextField under the unit and make it display the unit's name ONLY when selected.
  • Play a sound when a unit is selected

Advanced:

  • All of the above
  • When the player clicks a position, make selected units move to that position. (Hint: use an Array to know what units are selected.)

Only do the challenges you feel comfortable with!


Conclusion

Thankyou for reading this tutorial and I hope you learned something new. Also, I would also like to thank Tomas Banzas for the art he did!

If you have completed some of the challenges and would like to show off the results, please post a link in the comments - I'd love to see them!

Advertisement