# Laser Generator, Obstacles and Accurate Hit Detection

##### Tutorial Details
• Difficulty: Beginner
• Platform: Flash
• Language: AS3
• Software used: Flash Professional CS5
• Estimated Completion Time: 45 mins

Hi, friends. The main highlight of this tutorial is accurate hit detection of a generated laser. This kind of AI is useful in making action games, especially in the case of security intelligence with cameras, laser guns etc. So put your rocket on your back, countdown starts..

## Final Result Preview

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

## Step 1: Preparing Flash File

Open Flash and create a new Flash document (ActionScript 3.0).

Set stage size to any standard resolution. Mine is 500 x 350 px.

Set frame rate to 24 fps.

Save the file in a folder of your choice.

## Step 2: Creating Laser Generator Device

Let’s now create a laser generator.

Draw a circle of radius 20, i.e. 40 x 40. Also, fill it with some nice radial gradient color.

Now we need to convert this circle into a Flash symbol so that we can control it with ActionScript.

Select the circle and press F8 or go to Modify > Convert to Symbol. Select Movie Clip for the symbol type. Also set the registration point to centre so that the laser generator will rotate from its centre. Type laserGenerator_MC into instance name field and then last but not least check “Export for ActionScript” in “Advanced” group so that we can access laser generator from our document class which we are going to meet soon.

After setting all the above options press OK. Press OK again for the dialog box showing the warning for class definition. This will create a class definition for laser generator at runtime.

Now we do not need laserGenerator_MC symbol on to the stage since it is available in the Library panel with identifier name laserGenerator_MC. Therefore delete this symbol from the stage. Your stage should be empty now.

## Step 3: Improving the Look of Laser Generator

Now that we shall add a mouth to this generator to create some feel of a device. In the library panel double click on laserGenerator_MC symbol icon (left side of the symbol name) to go into edit mode. Add mouth to it as shown below.

Note: Do not change the position of the circle since we need to rotate it around its centre.

After adding a mouth to the generator, exit from the symbol edit mode and come back to main timeline.

Your rocket has left the ground. The laser generator device is ready and waiting to perform.

## Step 4: Preparing Document Class

To add a drama to our scene we need ActionScript. To act smartly we need document class.

In this step we shall create a basic structure of our document class.

For detailed explanation about Document Class check out this Quick Tip.

So create new ActionScript 3.0 file. Type the following code:

package  {
public class Laser_HitDetection{
public function Laser_HitDetection () {
// constructor code
}
}
}


Save this document class as Laser_HitDetection.as in the same folder where you saved your FLA for this tutorial. Nice take off. Your basic document class is ready.

## Step 5: Attach Document Class to FLA

In your FLA file access the Properties panel for the Document and type the name of the class in the Document Class field available under “Publish” group.

Now we are ready to communicate with FLA through this Laser_HitDetection.as document class.

## Step 6: Place and Align the Laser Generator at Stage Centre

We shall create an instance of laser generator from the library and place it to the centre of the stage.

Modify the Laser_HitDetection.as document class as shown below (highlighted lines):

package
{
import flash.display.Sprite;

public class Laser_HitDetection extends Sprite
{
var laserGun:Sprite; //Instance of laserGenerator_MC

//Constructor
public function Laser_HitDetection()
{
CreateLaserGun();

}

//Get and place laser generator from library
public function CreateLaserGun():void
{
laserGun = new laserGenerator_MC(); //Get it from the library

//Place laser generator at the centre of the stage
laserGun.x = stage.stageWidth / 2;
laserGun.y = stage.stageHeight / 2;
}
}
}


If you test the movie now, you will see our laser gun nicely placed at the centre of the stage.

## Step 7: Understanding CreateLaserGun() method

In the above code we used Sprite class to create an instance of Sprite object which will hold laser. For that we declare variable as:

var laserGun:Sprite;


Then we added a new method “CreateLaserGun()” in which we assigned an instance of laserGenerator_MC from the library to the above laserGun var as:

laserGun = new laserGenerator_MC();


After adding it to the stage we placed it at the centre of the stage as:

laserGun.x = stage.stageWidth / 2;
laserGun.y = stage.stageHeight / 2;


Finally we called this method from the constructor method of the document class as:

//Constructor
public function Laser_HitDetection()
{
CreateLaserGun();
}



Rocket is accelerating with full thrust. We shall activate this laser gun very soon which will project the laser. Before that we shall add some obstacles. Let’s go.

## Step 8: Adding Obstacles of Different Shapes

To experiment with hit detection we need some obstacles placed on the stage. So, on the stage draw different shapes resembling convex-concave surfaces, slope-climbing, and straight edges, as shown below:

## Step 9: Converting all Obstacles Into Single MovieClip

Now we shall put all these shapes in one symbol. Select all shapes at once and press F8 or go to Modify > Convert to Symbol. Select Movie Clip as the symbol type. Name this symbol obstacles_MC in name text field. Set registration point at centre. Also check “Export for ActionScript” so that we can access it from our document class.

After converting into MovieClip we have obstacles_MC in the library with the same identifier name. Simlilary as laserGenerator_MC we do not need this symbol on the stage, so delete it from the stage. Now your stage is empty.

## Step 10: Place and Align the Obstacles Symbol at Stage Centre

The way we placed our laserGenerator_MC on to the stage, at the center, similarly we shall place obstacles_MC symbol on to the stage. Modify the document class as shown below:

package
{
import flash.display.Sprite;

public class Laser_HitDetection extends Sprite
{
var laserGun:Sprite; //Instance of laserGenerator_MC
var obstacles:Sprite; //Instance of obstacles_MC

//Constructor
public function Laser_HitDetection()
{
CreateLaserGun();
CreateObstacles();
}

//Get and place laser generator from library
public function CreateLaserGun():void
{
laserGun = new laserGenerator_MC(); //Get it from the library

//Place laser generator at the centre of the stage
laserGun.x = stage.stageWidth / 2;
laserGun.y = stage.stageHeight / 2;
}

//Get and place obstacles from library
public function CreateObstacles():void
{
obstacles = new obstacles_MC(); //Get it from the library

//Place obstacles at the centre of the stage
obstacles.x = stage.stageWidth / 2;
obstacles.y = stage.stageHeight / 2;
}
}
}


Test the movie to see obstacles placed around the laser gun.

Your rocket is reaching terminal velocity. Now it’s time to activate the laser gun. It must generate the laser from it. Let’s do that now.

## Step 11: Projecting Laser

How will we mimic the laser? Any guess? …………… How about using some members of the Graphics class like lineStyle(), moveTo(), lineTo(). If you are familiar with these methods then your job is easy. For those who don’t know these methods, we are always with you. Let us see them in detail.

We shall add a new method ProjectLaser(). Let us modify our Laser_HitDetection document class as shown below:

//Constructor
package
{
import flash.display.Sprite;

public class Laser_HitDetection extends Sprite
{
var laserGun:Sprite; //Instance of laserGenerator_MC
var obstacles:Sprite; //Instance of obstacles_MC

var laser:Sprite;

var startX:Number; //x starting point of laser
var startY:Number; //y starting point of laser
var endX:Number; //x end point of laser
var endY:Number; //y end point of laser

//Constructor
public function Laser_HitDetection()
{
CreateLaserGun();
CreateObstacles();
ProjectLaser();
}

//Get and place laser generator from library
public function CreateLaserGun():void
{
laserGun = new laserGenerator_MC(); //Get it from the library

//Place laser generator at the centre of the stage
laserGun.x = stage.stageWidth / 2;
laserGun.y = stage.stageHeight / 2;
}

//Get and place obstacles from library
public function CreateObstacles():void
{
obstacles = new obstacles_MC(); //Get it from the library

//Place obstacles at the centre of the stage
obstacles.x = stage.stageWidth / 2;
obstacles.y = stage.stageHeight / 2;
}

//Project a laser from laser generator device
public function ProjectLaser():void
{
laser = new Sprite();

//Set origin of the laser as the centre of the laser gun
startX = laserGun.x;
startY = laserGun.y;

//Set end point of the laser
endX = startX + 230;
endY = startY;

//Draw laser
laser.graphics.lineStyle(1, 0xFF0000);
laser.graphics.moveTo(startX, startY);
laser.graphics.lineTo ( endX, endY );
}
}
}



Test the movie.

The rocket is right there up in the sky. The laser gun has started projecting the laser. How did that happen? Let’s try and understand the above code in the next step.

## Step 12: How is the Laser Projected?

In the above step we successfully projected a laser. For that we performed the following tasks:

First, we declared five new variables:

var laser:Sprite;

var startX:Number; //x starting point of laser
var startY:Number; //y starting point of laser
var endX:Number; //x end point of laser
var endY:Number; //y end point of laser


Second, we added a new method ProjectLaser():

public function ProjectLaser():void
{
laser = new Sprite();

//Set origin of the laser as the centre of the laser gun
startX = laserGun.x;
startY = laserGun.y;

//Set end point of the laser
endX = startX + 230;
endY = startY;

//Draw laser
laser.graphics.lineStyle ( 1, 0xFF0000 );
laser.graphics.moveTo ( startX, startY );
laser.graphics.lineTo ( endX, endY );
}


## Step 13: Understanding ProjectLaser() Method

In the above method first we created an empty Sprite object to hold the laser and also added it to the stage as shown below:

laser = new Sprite();


As we wanted the laser to start projecting from the laser gun, we assign laser gun’s X value to startX and Y value to startY as shown below:

startX = laserGun.x;
startY = laserGun.y;


(Later we provided these values to the moveTo(startX, startY) method which we are going to meet soon.)

Then we defined endX and endY:

endX = startX + 230;
endY = startY;


Values assigned to above variables are temporary values. We used them just to show the basic projection of a laser. In coming steps we shall modify these values by applying some simple math. These values are key to making perfect hit detection of the laser. We shall study them later in this session.

And now the important part of this method. Drawing a straight line within laser sprite object to mimic the projected laser.

First we handled the style of the line to be drawn as shown below:

laser.graphics.lineStyle ( 1, 0xFF0000 );


This lineStyle() method is used to control the styling of the stroke of the drawing object such as line, rectangle, oval etc. You can provide maximum of eight arguments to this method. If not specified default values are assigned instead. For our example we need only two arguments. The first argument is thickness of the line (i.e. 1) and the second argument is the color of the line (i.e. 0xFF0000, which is red).

For detailed explanation of this method check out the Adobe help doc on “lineStyle(args..)” method.

Then we placed the starting point of the line as shown below:

laser.graphics.moveTo ( startX, startY );


startX and startY ensures that the starting point must be the centre of the laser gun.

After that we finsihed up the line:

laser.graphics.lineTo ( endX, endY );


Remember that these endX and endY are temporary values just to show the projection. We need them to get adjusted if any obstacle comes in the way of laser. We shall do that math in coming steps.

So, we drew a line from (startX, startY) to (endX, endY).

The rocket is going and going. See those landscapes, waterscapes..

Now, it’s time for the real action. Hit detection with obstacles.

## Step 14: Hit Detection with Obstacles

Now, we are equipped with a laser gun. We also have several obstacles. We are at the level where we can add hit detection which will certainly add the meaning to the scene.

You might be thinking that this highly accurate hit detection will require complex math. If so then you are wrong. It simply uses the hitTestPoint() built in method of ActionScript along with a for loop. The complex math behind perfect hit detection is handled by this method. You only need to utilize this method and a for loop in a smart way.

We are going to make some important changes to our document class mainly to ProjectLaser() method and some new vars, so observe and apply it carefully. Let us modify it as shown:

var rad:Number = Math.PI/180; //Used to calculate angle in radians
var maxDist:Number = 250; //maximum distance to be travelled by the laser
var adjustedDist:Number; //new maximum distance if any obstacle comes in a way


Then modify ProjectLaser() method by adding for loop as shown below (also note that now endX and endY are inside for loop):

//Project a laser from laser generator device
public function ProjectLaser():void
{
laser = new Sprite();

//Set origin of the laser as the centre of the laser gun
startX = laserGun.x;
startY = laserGun.y;

{
//Trigonometry to aim the laser w.r.t laser gun's rotation
endX = laserGun.x + Math.cos ( laserGun.rotation * rad ) * adjustedDist;
endY = laserGun.y + Math.sin ( laserGun.rotation * rad ) * adjustedDist;

//calculate hit test
if ( obstacles.hitTestPoint ( endX, endY, true ) )
{
break;
}
}

//Draw laser
laser.graphics.lineStyle( 1, 0 x FF0000 );
laser.graphics.moveTo( startX, startY );
laser.graphics.lineTo ( endX, endY );
}


Test the movie.

Boom…. I am sure. Looking at this effect you are inspired to create a Flash Game having security intelligence. Perfect AI, to develop interesting game in Flash.

## Step 15: How the Hit Detection Happened

First of all we added new vars to our document class as shown:

var rad:Number = Math.PI/180; //Used to calculate angle in radians


The above var is used in formula to calculate an angle in radians.

The formula is, radians = degrees * Math.PI/180. More info here. We used this formula in our code, in these lines:

endX = laserGun.x + Math.cos ( laserGun.rotation * rad ) * adjustedDist;
endY = laserGun.y + Math.sin ( laserGun.rotation * rad ) * adjustedDist;


In laserGun.rotation * rad, degrees = laserGun.rotation, and rad = Math.PI/180.

Second, we created a var for the maximum distance to be travelled by the laser:

var maxDist:Number = 250; //maximum distance to be travelled by the laser


This var decides the maximum distance to be travelled by the laser. Since it is not necessary to draw laser beyond visible area, we define a nice end point. This var will do what’s needed.

Third, we have a var for the current distance of the laser at the time of intersection with any obstacle.

var adjustedDist:Number; //new maximum distance if any obstacle comes in a way


When any obstacle comes in the way of laser, the laser is blocked rather than traveling to maximum distance.

The distance after blocking a laser is nothing but the adjusted distance depending on the situation.

The for loop and hitTestPoint() each play an important role in calculating this distance.

Fourth, we modified ProjectLaser() method by adding ActionScript’s hitTestPoint() along with a for loop. We reassigned endX and endY variables.

for (adjustedDist = 0; adjustedDist < maxDist; adjustedDist ++)
{
//Trigonometry to aim the laser w.r.t laser gun's rotation
endX = laserGun.x + Math.cos ( laserGun.rotation * rad ) * adjustedDist;
endY = laserGun.y + Math.sin ( laserGun.rotation * rad ) * adjustedDist;

//calculate hit test
if ( obstacles.hitTestPoint ( endX, endY, true ) )
{
break;
}
}


The for loop ensures that the adjusted distance will be increased up to maximum distance. You might be thinking “What is the fun in making adjusted distance equal to maximum distance?”

Actually, this adjusted distance is allowed to match the maximum distance naturally but as soon as it hits any obstacles (which is detected by hitTestPoint() method) this distance is marked as maximum distance for that current situation. Thanks to hitTestPoint() for making the task so simple.

We also reassigned endX and endY values as:

endX = laserGun.x + Math.cos ( laserGun.rotation * rad ) * adjustedDist;
endY = laserGun.y + Math.sin ( laserGun.rotation * rad ) * adjustedDist;


The trigonometry functions Math.cos() and Math.sin() are used to calculate the angle of laser w.r.t laser gun rotation.

In simple form, it takes care of aiming the laser where the laser gun is looking. It is important that laser gun and laser are both in sync. So whenever the laser gun is rotated the laser will follow the rotation.

Finally the climax of the scene:

if ( obstacles.hitTestPoint ( endX, endY, true ) )
{
break;
}


hitTestPoint() method takes three parameters, out of which the first and second parameters are necessary and the third one (shapeFlag) will be left as the default (i.e. false) if not specified.

In our example, shapeFlag is set to true since we want hit detection with respect to the exact shape of the target object (i.e. obstacles). If this value is set to false the hit detection occurs with respect to the bounding box of that object and not the exact shape.

The first and second parameters of hitTestPoint() define a point (x, y) at which to check for intersection with the display object. In our case obstacles is that display object, and endX and endY represents the point of intersection on the stage.

Unclear? Right. To simplify we shall put the logic in sequence as follows:

1. The for loop allows the projection of the laser to continue (by updating endX and endY) if within maximum distance.
2. hitTestPoint() is waiting to break the for loop as soon as it sees the intersection. Once the for loop is broken, endX and endY are frozen.
3. Finally these frozen endX and endY are passed to the graphics.lineTo() method.

## Step 16: Applying Rotation to Laser Gun

To add rotation to laser gun we need to perform some major changes:

1. Re-Structuring ProjectLaser () method.
2. Placing the entire hit detection logic in new method HitTest().
3. Adding new statement laser.graphics.clear() in the for loop.
4. Import statement import flash.events.Event

First we shall restructure the ProjectLaser() method by shifting the entire hit detection logic in new method HitTest().

Then we shall add laser.graphics.clear() statement before laser.graphics.lineStyle( 1, 0xFF0000 ) statement inside the for loop of new method HitTest(). This will remove the old projection of the laser from the stage when the laser gun will start rotating.

Let’s see how it will look after making all four major changes:

public function ProjectLaser():void
{
laser = new Sprite();

//Set origin of the laser as the centre of the laser gun
startX = laserGun.x;
startY = laserGun.y;
}

//Hit test
public function HitTest():void
{
{
//Trigonometry to aim the laser w.r.t laser gun's rotation

//calculate hit test
if (obstacles.hitTestPoint(endX,endY,true))
{
break;
}
}

//Draw laser
laser.graphics.clear(); //Removes the old laser projection
laser.graphics.lineStyle( 1, 0xFF0000 );
laser.graphics.moveTo( startX, startY );
laser.graphics.lineTo ( endX, endY );
}


You might be asking why we did such major changes? The only reason is ENTER_FRAME event.

To apply continuous rotation we shall add a new method, LaserGunRotation( evt:Event ) which is activated by ENTER_FRAME event (meaning it is run 24 times a second, since our frame rate is 24fps). When this event is used, you must be careful to add only such properties those we want to change over period of time. Avoid putting in those values which remain constant throughout the execution.

In our case, if you observe old ProjectLaser() method, it has:

laser = new Sprite();


Imagine if you add above statements in a method which uses ENTER_FRAME event; then a new laser Sprite object would be created and added to stage repeatedly — 24 times every second.

This is absolutely unnecessary. Therefore we restructured ProjectLaser() method and added new method HitTest(). You can rename ProjectLaser() method to InitializeLaser() since it no longer projects the laser. Now it only creates the empty holder for the laser and defines its starting point. The projection is handled in a new method, HitTest().

Now let us see the new method LaserGunRotation( evt:Event ). Before that add the following import statement at the start of the document class:

import flash.events.Event;


//Rotate Laser Gun
public function LaserGunRotation( evt:Event ):void
{
laserGun.rotation += 0.5;

HitTest();
}


Also, do not forget to call this method with an ENTER_FRAME event inside constructor function as shown below:

//Constructor
public function Laser_HitDetection()
{
CreateLaserGun();
CreateObstacles();
ProjectLaser();

}


This sets it up to run the LaserGunRotation() function 24 times a second.

Test the movie.

The rocket has already penetrated clouds. See the beautiful Earth.

## Step 17: Adding Control to the Accuracy of Hit Detection

In this step we shall add a control to adjust the accuracy of the hit detection. This is important since you do not need the precise hit detection every time; you might need an average level of hit detection. This will also help in reducing the CPU consumption at the time of hit detection.

We shall introduce a new variable tolerance as:

var tolerance:Number = 1;


Then we shall modify the for loop’s increment statement as:

for (adjustedDist = 0; adjustedDist < maxDist; adjustedDist += tolerance)


Now the for loop will look like:

for (adjustedDist = 0; adjustedDist < maxDist; adjustedDist += tolerance)
{
//Trigonometry to aim the laser w.r.t laser gun's rotation

//calculate hit test
if (obstacles.hitTestPoint(endX,endY,true))
{
break;
}
}


This means that instead of checking for a collision at every pixel of the laser line, we are only checking for a collision at every other pixel, or every third pixel, etc.

Lowering the value for “tolerance” will increase the accuracy of the hit detection but require more CPU power. Try experimenting with different values for “tolerance”.

Friends, it’s time to leave the rocket and open the parachute. Land safely on the ground and start using the above technique in your Flash games and applications. Enjoy!

## Conclusion:

In this tutorial we mainly saw the perfect utilization of hitTestPoint() and a for loop to create accurate hit detection without using any complex math.

This effect can be used in a security type action game where cameras and laser guns are required.

• randygland

I don’t know why, but every time i see function names begin with a capital letter, a little piece of me dies

• Rahul

I like to keep variable name starting with small letter and function with capital letter. It differentiates functions and variables from each other.

By the way its all about the final effect produced by the script and not the reading of the script. I suggest to concentrate on logic and not the grammar.

• ExoNig

Perhaps, but it’s wise to encourage and spread good programming practices. The standard’s in most language reserve the capital letter for object definition’s.

• Nikita

Cool tutorial, just one note: It might be a good idea to move the sine and the cosine calculation out of the for loop.
Trigonometric operations are expensive, and there’s no point in calculating them hundreds of times each frame when you can do it once.

var cos:Number = Math.cos ( laserGun.rotation * rad );
var sin:Number = Math.sin ( laserGun.rotation * rad );
{
//Trigonometry to aim the laser w.r.t laser gun’s rotation
endX = laserGun.x + cos * adjustedDist;
endY = laserGun.y + sin * adjustedDist;
//rest of code omitted
}

Cheers :)

• Rahul

Hi, Nikita

Thanks for your good suggestion. I totally missed out that. And one more addition as, declare those vars (cos and sin) not inside the function but at start of the script.

As you are pointing towards trigonometric operations as expensive, How about using basic vector calculations? However it will add some more vars and lines for calculations for multiplication and division i guess.

Thanks once again.

• http://gods-of-art.com S3bY

Great tutorial!

• Rahul

Thanks for motivation.

• http://www.treeshore.com prakash

lot of strategic techniques. useful resource really thanks and its highly impressive

• Rahul

Glad to hear that you found this technique useful.

• http://weightt-loss.blogspot.com selec

Great tutorial! thank you!

• Rahul

Thanks for appreciation.