Create heat-seeking missiles with ActionScript

This tutorial will show you how you can create heat-seeking missiles using ActionScript. We will be using the explosion code from the previous tutorial, which I recommend you read. In the example below, clicking the mouse creates a missile which seeks the target. The target is dragged by the mouse. Upon reaching the target, the missile explodes. No matter where the target is moved, the missile will seek it out relentlessly.

You don’t have to understand how the explosion code works in this tutorial, although a good knowledge of trigonometry will help.

(Click with the mouse anywhere inside the movie to create a new missile.)


Before we delve into the code, let’s sort out our document properties (CTRL+J). Set the background color to #999999, and the frame rate to 20. The default document size is fine.

The first thing to do is set the four boundaries of the game world. To make the extent of the game world obvious I have made it slightly smaller than the Stage, and given the Stage a different background color. You will notice that the fragments from the explosions do not make it beyond the boundaries without being removed from the Stage. It’s easy to adjust the size of the game world by changing the four boundary variables:

1
2
3
4
5
/* GLOBAL VARIABLES */
_global.gLEFT = 20;
_global.gTOP = 20;
_global.gRIGHT = Stage.width - 20;
_global.gBOTTOM = Stage.height - 20;

Following the global variables are three simple function definitions. The first two need little explanation—here they are:

7
8
9
10
11
12
13
14
15
/* FUNCTION: Converts radians to degrees */
function rad2deg(radians:Number):Number {
  return radians * 180 / Math.PI;
}  
 
/* FUNCTION: Converts degrees to radians */
function deg2rad(degrees:Number):Number {
  return degrees * Math.PI / 180;
}

These functions will come in handy, as you will see. I introduced you to randRange( ) in the previous tutorial, and here it is again:

17
18
19
20
21
/* FUNCTION: Returns a random number between min and max (inclusive) */
function randRange(min:Number, max:Number):Number {
  var randomNum:Number = Math.floor(Math.random() * (max - min + 1)) + min;
  return randomNum;
}

We use explosion( ) to create the explosions caused by the missiles. There are a couple of things to note about this function: Firstly, it has five properties which are used to control the characteristics of each explosion. I could have made them timeline variables, but instead I have made them properties of explosion( ), since only it need access them. Secondly, it has two parameters, originX and originY. Together they represent the x and y location from which the explosion will appear to originate.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/* FUNCTION: Creates an explosion */
explosion.maxSpeed = 25;
explosion.minSize = 4;
explosion.maxSize = 10;
explosion.minFragments = 10;
explosion.maxFragments = 50;
function explosion(originX:Number, originY:Number):Void {
  var totalFragments:Number = randRange(explosion.minFragments, explosion.maxFragments);
  var fragment_mc:MovieClip;
  var depth:Number = this.getNextHighestDepth();
  for (var i:Number = 0; i < totalFragments; i++, depth++) {
    fragment_mc = attachMovie("Fragment", "fragment" + depth, depth);
    fragment_mc._x = originX;
    fragment_mc._y = originY;
    fragment_mc._width = fragment_mc._height = randRange(explosion.minSize, explosion.maxSize);
    while (!fragment_mc.speedX) {
      fragment_mc.speedX = randRange(-explosion.maxSpeed, explosion.maxSpeed);
    }
    while (!fragment_mc.speedY) {
      fragment_mc.speedY = randRange(-explosion.maxSpeed, explosion.maxSpeed);
    }
    fragment_mc._alpha = randRange(10, 100);
    fragment_mc.cacheAsBitmap = true;
 
    fragment_mc.onEnterFrame = function():Void {
      this._x += this.speedX;
      this._y += this.speedY;
 
      if (this._x < gLEFT || this._x > gRIGHT || this._y < gTOP || this._y > gBOTTOM) {
        this.removeMovieClip();
      }
    };
  }
}

The last function, createMissile( ), does the tough job of creating the missiles, setting them up and sending them on their way. The result of calling createMissile( ) is an autonomous movie clip, whose soul purpose in life is to seek out and destroy it’s target. Let’s examine this function step-by-step.

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/* FUNCTION: Creates and initializes heat-seeking missiles */
createMissile.maxSpeed = 30;
createMissile.accel = 2;
function createMissile(target_mc:MovieClip, xPos:Number, yPos:Number):Void {
  var depth:Number = _root.getNextHighestDepth();
  var missile_mc:MovieClip = attachMovie("Missile", "missile" + depth, depth);
  missile_mc._x = xPos;
  missile_mc._y = yPos;
  missile_mc.speed = 0;
 
  missile_mc.setRotation = function():Void {
    var dy:Number = target_mc._y - this._y;
    var dx:Number = target_mc._x - this._x;
    this._rotation = rad2deg(Math.atan2(dy, dx));
  };
 
  missile_mc.onEnterFrame = function():Void {
    this.setRotation();
 
    if (this.speed < createMissile.maxSpeed) {
      this.speed += createMissile.accel;
    }
    this._x += Math.cos(deg2rad(this._rotation)) * this.speed;
    this._y += Math.sin(deg2rad(this._rotation)) * this.speed;
 
    if (this.hitTest(target_mc)) {
      explosion(target_mc._x, target_mc._y);
      this.removeMovieClip();
    }
  };
}

Firstly, two properties of createMissile( ) are set. The first, maxSpeed, sets a speed limit for the missiles. The second, accel, determines how quickly the missiles will accelerate towards their target. The function has three parameters: target_mc holds a reference to the movie clip which the missile should seek. The missile is given an initial x and y location with xPos and yPos. Next comes the body of the function.

depth is set to the next available depth, and is used to ensure that each missile gets a unique instance name and it’s own depth level. missile_mc is used to hold a temporary reference to the missile, as returned from attachMovie( ), so that it’s properties and methods can be set. For my missiles I made a 20×4 blue rectangle. The missile is given an initial x and y location with xPos and yPos. A property called “speed” is set to 0–since each missile will start from rest.

setRotation( ) has the very important job of making sure that the missile is always pointing in the direction of it’s target. It does this by finding the difference between the target and itself along the y-axis and stores this in dy, and then along the x-axis, which it stores dx. dy represents the opposite side, and dx the adjacent side, of a right triangle. These two values are passed as arguments to Math.atan2( ), which then returns an angle between positive pi and negative pi (which is equivalent to 180° and -180°). We then use rad2deg( ) to convert this angle in radians to an angle in degrees. The resulting angle is finally used to set the missile’s rotation.

When you create your missile movie clip symbol, make sure the missile graphic is lying on it’s side and pointing right. Otherwise you’d have to compensate in the code.

Last but not least, the missiles onEnterFrame handler is set. Firstly, setRotation( ) is called to point the missile in the right direction. The missile’s speed is then incremented so long as it is less than maxSpeed. Without setting a speed limit, the missiles would accelerate on every frame until they hit their target. Experiment with the value of maxSpeed to get a behavior that your happy with. Obviously the higher maxSpeed is, the harder it will be to evade the missiles. The x speed component is calculated by passing _rotation - converted to radians by deg2rad( ) - to Math.cos( ), the return value is then multiplied by speed. The same applies to the y speed component, with Math.sin( ) being used instead of Math.cos( ). These two components are added to the missiles current x and y location. This moves the missile in the direction of it’s target. hitTest( ) is used to check for a collision with the target. If a collision takes place, an explosion will occur from the target’s x and y location. The missile will then remove itself from the Stage by invoking it’s removeMovieClip( ) method.

Now at last we can put all the code discussed so far to good use. We do this in the main program logic.

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* MAIN PROGRAM LOGIC */
var gameBG_mc:MovieClip = _root.createEmptyMovieClip("gameBG", 0);
gameBG_mc.beginFill(0x222222);
gameBG_mc.moveTo(gLEFT, gTOP);
gameBG_mc.lineTo(gRIGHT, gTOP);
gameBG_mc.lineTo(gRIGHT, gBOTTOM);
gameBG_mc.lineTo(gLEFT, gBOTTOM);
gameBG_mc.endFill(gLEFT, gTOP);
 
var target_mc:MovieClip = attachMovie("Target", "target", _root.getNextHighestDepth());
var startX:Number = (gRIGHT - gLEFT) / 2 + gLEFT;
var startY:Number = (gBOTTOM - gTOP) / 2 + gTOP;
startDrag(target_mc, true);
Mouse.hide();
 
onMouseDown = function():Void {
  createMissile(target_mc, startX, startY);
};

Notice that from line 91 to 97, a movie clip is created and a filled rectangle is drawn inside of it with dimensions equal to the game world. This acts as a visual representation of the game world’s true extent.

Next, target_mc becomes a reference to the target movie clip that is attached to the Stage via attachMovie( ). I simply made my target a 10×10 red circle. Together, startX and startY represent the x and y location from which each missile will originate (I’ve set them to the absolute center of the game world). The target is made draggable by calling startDrag( )—passing true as the second argument ensures that the target is dragged with it’s center coinciding with the mouse’s position. The mouse pointer is hidden with a call to the hide( ) method of the Mouse class. All that is left to do is put a call to createMissile( ) in the onMouseDown handler, which is on the root timeline. Whenever the mouse is clicked over the Stage, createMissile( ) creates for us a heat-seeking missile which immediately begins to hunt down it’s target. How long can you evade the missiles for?

I’m sure the logic of createMissile( ) could be used to create any number of interesting visual effects that involve one movie clip chasing another.

Feel free to link to our content. However, we do not permit any copying.

25 Responses to “Create heat-seeking missiles with ActionScript”


  1. 1 Erik

    Really great! I’ve been searching for a tutorial that uses alot of math.

  2. 2 TechnoMono

    Glad you like it. I have a lot more planned :)

  3. 3 krutika.deshpande

    excellent work…i want the same but with duppliacte movie clip so that it is run by itself rather than having to click…if u have one pls mail me…..thanks

  4. 4 ahref

    @krutika.deshpande

    duplicatemovie and attachmvoie are essentially the same. duplicate movie however requires the movieclip to be on stage whereas attachmovie gains it from the libary.

    createMissile is a function and can therfore be called in a huge amount of ways.

    eg when a player presses a fire missile button, when the ai script decides it would be best to fire a missile

    so there is no need for a duplicatemovie version

  5. 5 deena

    hi nice

  6. 6 Joe

    My problem is naming the movie clips I namedit target and named the other one missile. It wont work for me. Help?

  7. 7 Danny

    Doesnt work for me got flash 8.0 and if i execute nothing happend and i get no errors

  8. 8 Ultric

    Could you give a link to the completed version so I can see where to put everything? I tested it and the missile just sat there.

  9. 9 diddent work

    diddent work at all working with flash cs3 pro
    using as2

  10. 10 BoJaN

    hmm i tried making a class with it and importing it it gave a few errors at first which i fixed(just the explosions variables needed moving) and got no errors but when i try to execute a function it doesnt run at all i even tried a trace in the function and that wasn’t triggered even though just above where i execute the function i have a trace that’s triggered. can somone try making a working .as file and posting it here? ill keep trying to get this one working, thanks.

  11. 11 TechnoMono

    @BoJaN

    If you want to take an object-oriented approach, I’d recommend converting the script to AS 3.0. If your having trouble implementing the script as a class, then I’m guessing your new to object-oriented programming (at least in AS 2.0).

    You can learn all about OOP in AS 2.0 from here:

    http://www.moock.org/lectures/introToOOP/

    Hope this helps :)

  12. 12 BoJaN

    Hi, thanks for the reply but I figured it out a while ago,
    I was importing it but not starting the class with the
    “var func:miscFunctions = new miscFunctions();” line it works great! I love the explosions and im making a basic tower defence game with it just for fun Thanks again!

  13. 13 TechnoMono

    @BoJaN

    That’s great BoJaN. Good luck with your game!

  14. 14 mail090

    how come when i do it my mouse disapears?????

  15. 15 TechnoMono

    Take a look at line 103 of the code. I’ve invoked Mouse.hide(), which hides the mouse pointer ;)

  16. 16 Anonymous

    I don’t get it. Can someone send me the *.fla file of it? Preferably the writer of this tutorial please.

  17. 17 boston

    I have a different set of code that’s about 4 times shorter than this but does (on my computer) a better job of following the mouse. I’ll post it up later since I’m on a different computer right now. It involves dividing the distance between the missile and the mouse (or any object) instead of using a bunch of trig. In fact, it does a better job of following the mouse, since, for this missle, it’s faster hasing the mouse when the mouse is shifted to the right, and slower when the mouse is moved left.

  18. 18 TechnoMono

    @boston

    I wasn’t concerned with efficiency when writing this tutorial, only making the tutorial clear and easy to follow. However, I’d like to see your solution. It sounds very interesting.

  19. 19 Anon

    hi, thanks for the tutorial

    important question: if i want to make the missile go in a “greater angle”, what should i do for that to happen?

    what i mean is: i don’t want the missile to be able to make such tight turns. as it is now i can speed by the missile very close with my mouse and the missile still keep up and will travel in the opposite direction in no-time. not very realistic.

    so how do i give the missile a turn-rate? thanks.

  20. 20 TechnoMono

    @Anon

    I actually tried something like that originally, but I found it didn’t really work that well. If the missiles turn too slow, they overshoot the target. On the other hand, if they turn too quickly, it looks a little odd.

    Having said that, it’s unusual for objects in a game to move as fast as the mouse pointer (unless of course their attached to it). So this direct, and perhaps unrealistic method, works quite well.

    Most gamers will excuse the lack of realism so long as the game plays well, and above all, is fun. This approach also makes coding the missiles simpler, and that’s always a good thing :)

  21. 21 KiLl3r

    Love the tutorial but was wondering if its possible that once fired the missile just carrys on instead of following the mouse? So just a shoot and forget kinda thing?

    Cheers

  22. 22 TechnoMono

    @KiLl3r

    Instead of calculating the missiles speed along the x and y axes and their rotation on every frame, you would set the speeds and rotation when the missiles are first created, based on the location of the target. Then, in the onEnterFrame handler, you’d just apply acceleration and velocity.

  23. 23 Dexter Blakely

    how come everytime my missile gets close the game freezes up

  24. 24 Marotzke

    I had these problems too, at the beginning (nothing seems to work but no error; then - when target is hit, freeze); but if you name all three movieclips in the right way, it will work.

    To be really sure I copy&pasted the code - and it works :-)

    thx for this

  25. 25 F

    Thanks for sharing..! :)

    F, Amsterdam

Comments are currently closed.