Homing Missile mini-tutorial
A Flash Developer Resource Site

Results 1 to 20 of 20

Thread: Homing Missile mini-tutorial

  1. #1
    Coder-at-large
    Join Date
    May 2001
    Posts
    99

    Wink

    How to do homing missiles:

    Several weeks ago someone asked how to make homing missiles home. I gave an answer, and offered to elaborate if they pestered me. They pestered me, but between job, going out of town, and real life, I didn’t get to it. But people keep asking about this sort of thing, so I figured I might as well elaborate, since it seems to be something people want to know how to do.

    So I went and wrote a quickie tutorial-thing on it.

    Note: I have an example .fla that I went and threw together for this. You can view/run the example from http://www.cloudnet.com/~mathonwy/fl...sile_demo.html, or you can view the source code at http://www.cloudnet.com/~mathonwy/fl...ssile_demo.fla. I left the source code full of (hopefully) helpful comments, so if you want to just ignore the rest of what I’m posting here, and jump right in, then go ahead. Otherwise, read on!

    Another note: This is written with the idea of making homing missiles that home in on the player. But there is no reason that the ideas presented here have to be limited to missiles. Most of what I’m about to write about can be used for just about any kind of situation where you want one thing to move towards or follow another thing. So don’t be locked into the idea of missiles just because that’s what I wrote for the title of this thread. Be creative!


    Ok, the basic idea behind homing missiles is simple. You have a missile. It has a target. You want the missile to go to the target. But it can’t go there instantly, because that tends to piss off your players. So you move it there slowly, over many frames, so that when it hits them, they have no one to blame but themselves. The trick then, is for any given frame, knowing where and how the missile will move. Once we have that figured out, then the rest is easy: We just move the missile like that every frame, and voila! Instant player-killing mean thing. So, let’s look at how this works.

    (For the rest of everything I write, assume that ‘missile’ is a movie clip that represents our missile, and ‘target’ is a clip that is what ‘missile’ is moving towards.)

    [Edited by Mathonwy on 07-17-2001 at 12:23 AM]

  2. #2
    Coder-at-large
    Join Date
    May 2001
    Posts
    99

    Warcraft II missiles

    First of all, there is what I call the dumb missile in the tutorial example file. Also known as the “Warcraft II” missile. This is because, just like all of the characters in Warcraft, it can only move in 8 directions. On the other hand, this is an extremely good place to start conceptually, since missiles don’t get much easier than this. The code is extremely simple:
    Code:
    if (missile._x<target._x)
    	missile._x+=20;
    
    if (missile._x>target._x)
    	missile._x-=20;
    
    if (missile._y<target._y)
    	missile._y+=20;
    
    if (missile._y>target._y)
    	missile._y-=20;
    This translates very nicely into direct english:
    If the missile is left of the target, move the missile right.
    If the missile is to the right of the target, move the missile left.
    If the missile is above the target, move the missile down.
    If the missile is below the target, move the missile up.

    Yay. Easy. Unfortunately, it doesn’t look especially cool. So I recommend using this only for demonstration purposes only. It does, however illustrate very nicely exactly what we want our missile to do. For any given frame, it is extremely easy to tell exactly what the missile will do. And that is what we want. So next lets look at how to make our missiles look a little better.

  3. #3
    Coder-at-large
    Join Date
    May 2001
    Posts
    99

    Direct, non-swerving missiles

    The missiles labeled “better missiles” in the example demonstrate the next level up in missile design. Again, the code is fairly simple. It might be a little weird to understand, however, since it involves a little linear algebra. I’ll try to take it slow:

    Code:
    Missile_speed=20;
    
    dx=Target._x-Missile._x;
    dy=Target._y-Missile._y;
    
    distance=Math.sqrt((dx*dx)+(dy*dy));
    
    dx/=distance;
    dy/=distance;
    
    Missile._x+=dx*Missile_speed;
    Missile._y+=dy*Missile_speed;
    Ok, first we are constructing a vector, (dx,dy). For those of you who don’t understand exactly how vectors work, think of it like this: Vectors are basically things that you add to points to get new points. Yes, this sounds trivial, but it will be useful in a moment. In particular, if we add (dx,dy) to missile._x, missile._y, then we would be directly on top of the target. (The way you add vectors to points, by the way, is you add the components separately. So for example, if we added (dx,dy) to the missile’s position, we would get missile._x + dx, missile._y+dy) The problem with using (dx,dy) as it is, is that it will go all the way to the target instantly. (Which, as was noted above, really bugs the player) So we want to move it only a little bit of the way towards the target. We do this with the help of a new variable, called ‘distance’. ‘distance’ represents the distance between the missile and the target. (Calculated with everyone’s favorite, the Pythagorean theorem.) So if the missile moved by (dx,dy), it would move ‘distance’ pixels in one frame. We want it to move less. So we divide (dx,dy) by ‘distance’. Our new version of (dx,dy) will only move the missile towards the target by one pixel. (Since it was moving by ‘distance’, and we divided it by ‘distance’, and anything divided by itself equals 1) One pixel at a time is a bit too slow, so we multiply (dx,dy) by missile_speed (how fast we want the missile to go) before we add it on to the missile’s ._x,_y properties. This way it will move ‘missile_speed’ pixels at a time. (Since it was moving 1 pixel at a time before, and missile_speed * 1 = missile_speed)

    Ok, whew. Math over. You can look up now. If you don’t want to deal with the math, then just take my word for it that
    Code:
    Missile._x += (dx/Distance) * missile_speed
    Missile._y += (dy/Distance) * missile_speed
    will move the missile directly towards the target by missile_speed pixels. But if you can stomach the math, I highly recommend trying to understand it. After all, you’d much rather be able to come up with this stuff yourself, than have to depend on copying it down from other sources. (Like handy tutorials. )

    Anyway, the sum total of all that math can be seen by checking out the “better missiles” section of the example: The missile moves directly toward the target each frame, no matter where the target is. This is fairly straightforward, and makes a serviceable missile or enemy, but it has a few problems. First of all, if the missile moves faster than the target does, then there is no possible way to dodge it. It just can’t happen. Also, if the target can move much FASTER than the missile, then it looks a little odd as it makes hairpin turns. The problem is that it looks like what it is: A very simplistic way of making things move. So lets move on to…

  4. #4
    Coder-at-large
    Join Date
    May 2001
    Posts
    99

    Cool momentumy missiles!!!

    COOL missiles. Or at least that’s what I call them in my examples. This is a much better model of missile movement, since it takes momentum into account, for more realistic looking paths. Like the last one, it involves some math, but if you survived the last way of doing missiles, then this should be a breeze. So, without further ado, here is the code:

    Code:
    Missile_speed=20;
    
    Missile_turning=6;
    
    dx=Target._x-Missile._x;
    dy=Target._y-Missile._y;
    
    distance=Math.sqrt((dx*dx)+(dy*dy));
    
    dx/=distance;
    dy/=distance;
    
    vx+=dx*Missile_turning;
    vy+=dy*Missile_turning;
    
    velocity=Math.sqrt((vx*vx)+(vy*vy));
    
    if (velocity>Missile_speed)
    {
    	vx=(vx*Missile_speed)/velocity;
    	vy=(vy*Missile_speed)/velocity;
    }
    
    Missile._x+=vx;
    Missile._y+=vy;
    Ok, the primary difference between the last way to do missiles and this way is that here we keep track of two extra variables, vx and vy. These are, as you might have guessed, another vector. They represent the current velocity of the missile at any given time. This works out through more vector math: Instead of directly adding dx and dy to the missile’s position, we add them to vx and vy. So let’s look at how this works: Assume for the moment that the missile is completely stationary. (vx,vy) = (0,0) Notice that instead of multiplying dx,dy by missile_speed, this time we multiply them by missile_turning. Which in this case is 6. So the first frame, dx and dy end up being a vector with a magnitude (distance) of 6, pointing directly toward the target. Since we add dx and dy to vx and vy, and then add vx,vy to missile._x, missile._y, the net result is that the missile moves 6 pixels towards the target. Woo. Just like before. But now, things get interesting. Because, on the NEXT frame, the missile already has a vx and vy. So when we add (dx,dy) to them, (which again, have a magnitude of 6), the net result is that the missile moves 12 pixels towards the target. So it’s speeding up. And similarly, next time, it will move 18, and after that 24, etc. Or at least it would, except that we cap the missile’s speed out at 20, so that it has a maximum speed. That’s what the whole (velocity>Missile>speed) part does. Velocity calculates the magnitude of vx, vy as a vector. If that is too big, then it divides the (vx,vy) vector by velocity, thus giving it a magnitude of 1. Then it multiplies it by the “correct” speed. This is just like before, where we changed the magnitude of the (dx,dy) vector to be whatever we wanted by dividing it by distance, and then multiplying. Again, if you don’t want to wade through the math, then feel free to just take me at my word. But again, I recommend trying to understand it, in case you want to do things like this on your own.

    An interesting fact is that the math here is almost exactly the same as if the target were a gravity well, and the missile were an object “falling” towards it. In fact, with a little patience, you can even get the missiles to go into “orbit” around the target.

    Anyway, the math is a little heavy, (linear algebra REALLY helps, you really need to understand what vectors are to really know what’s going on, I’m afraid) but the end result is a fairly nice missile movement. It has to swerve around, and can’t make hairpin turns anymore. And so it looks much cooler. And it’s actually possible to dodge, even if it moves faster than the player does. You can use “bull fighting” tactics on it, and move horizontally away from it.

  5. #5
    Coder-at-large
    Join Date
    May 2001
    Posts
    99

    Many many mighty missiles!

    Finally, we have the “many missiles” portion of the example. This is basically the “cool missiles”, except applied to 10 missiles at a time. I included this because I’ve noticed that a lot of people seem to have trouble dealing with lots of things moving at once, and so I thought I’d give them something to work from. The secret behind this is… the all powerful…. ARRAY. Yes, arrays are your friends. The thing that’s cool about them here is that you can just loop through all the elements, and do the math (which we just painstakingly waded through) to ALL the missiles at once. I’m not going to bother explaining the math in this code, since it’s exactly the same as in the “cool missiles” portion of this example. But just in case you don’t understand how the arrays work, here’s a quick rundown of everything I’m doing:

    First off, I have an “initialization” frame. It gets run once, and sets various variables, etc. In particular, it creates new arrays delay[], vxList[] and vyList[]. VxList and vyList each contain 10 elements. We have 10 missiles. No, this is not a coincidence. VxList[0] contains the vx value for the first missile. VyList[0] contains the vy value for the first missile. And so on, all the way up to vxList[9], vyList[9]. But what about delay? This is a new one. Delay is a varaible used to keep track of how long each missile has to wait to launch. This is so that they don’t all swarm out at exactly the same time. The number contained in delay[x] is the number of frames that missile x has to wait before launching.

    Now let’s look at the main loop frame. Everything here is exactly what we saw before, with just a few differences. First of all, there is the big for() loop. This runs through all 10 missiles, and does the math to all of them. Unless they have a positive delay value. If they have a delay value that is bigger than 0, then it just subtracts 1 from it, (thus moving it closer to 0) and does nothing else. If it has a delay value of =<0, then it does all that familiar math to it. The only other point of note is what happens when a missile hits. Before, we just went on to the explosion frame, and let the missile detonate. But we can’t do that here, or else all the missiles would pause while it detonated. So what we do is sneaky: We move the missile far away, and give it a delay value, so it won’t bother us for a while. And then, we put the explosion movie clip right where the missile was. So it looks like it goes boom. And it won’t be back until after the explosion has already gone away. Slick!

  6. #6
    Coder-at-large
    Join Date
    May 2001
    Posts
    99

    So in conclusion...

    And THAT is how we make homing missiles. Or at least how I make them. I know I probably lost some people on the math in the middle. If you have specific questions on how things worked, feel free to ask in this thread, and I’ll try to answer them. To everyone who hasn’t taken it yet, go take linear algebra. Honest! Math = cool, when programming games! If you directly copy any of my code into your game, then please at least give me credit. (hehe. Further trickery on my part to try to convince people to learn the math themselves: If you can write it yourself, then you won’t have to have my name on your cool game!)

    Enjoy, and I hope people find this helpful.

  7. #7
    Senior Member
    Join Date
    May 2001
    Location
    Sweden
    Posts
    197
    Your links didn't work for me for some reason. I'm too tired to read all your script and try to visualise too.

    If you're interested in the study of homing thingies I could send you the .fla for a game outcast I started working on. It uses a little trigonometry to aim the enemy ship at the player.

    http://www.rydeman.com/erik/skepp2.html

    I haven't got the .fla uploaded but tell me if you want it.

  8. #8
    Senior Member
    Join Date
    May 2001
    Posts
    425
    and just a side note, you might wanna add a code similar to this to the missils, to make them face the direction they are traveling.
    Im workin with this code, and i might have a method that will make them corkscrew (sidewinder missils) while traveling to the target.
    heres the rotation code i use--this is the 9th grade math version:
    note: this code has not been modified to work with the missils YET. Im workin on it, but im a little slow at math.
    Code:
    onClipEvent (enterFrame) {
        // Rotate the plane
        if (Key.isDown(Key.UP)) {
            this._rotation = this._rotation-2;
        }
        if (Key.isDown(Key.DOWN)) {
            this._rotation = this._rotation+2;
        }
        // move the plane in the dir. it is facing
        this._x = this._x-speedx;
        this._y = this._y-speedy;
        if (angle>=0 and angle<=90) {
            speedy = (angle/90)*2;
            speedx = 2-speedy;
        }
        if (angle>=91 and angle<=180) {
            speedy = ((180-angle)/90)*2;
            speedx = (-2)+speedy;
        }
        if (angle<=-91 and angle>=-179) {
            speedy = -(((180+angle)/90)*2);
            speedx = (-2)-speedy;
        }
        if (angle<0 and angle>=-89) {
            speedy = (angle/90)*2;
            speedx = -(-2+(-speedy));
        }
        angle = this._rotation;
        _root.angle = this._rotation;
    }

  9. #9
    Coder-at-large
    Join Date
    May 2001
    Posts
    99

    Bad link fixed. And a little more math.

    Bleah. The auto-URL-parser messed up the .fla url. (it added a '.' on the end.) All better now. Thanks for pointing out the bad link, Rydeman.

    And for anti-mater0:

    I left out rotation, since I figured I was throwing enough math at people in one sitting. If you wanted to make the missiles face the direction that they're going, then you'd probably need to use some trig. Since we have the x and y components of the vector that make up the direction that the missile is going in, we can easily convert that into an angle via trig.

    So to add angles to, say, the "cool missiles", you'd need something like
    Code:
    missile._rotation=(Math.atan2(vx,vy)/Math.Pi)*360;
    (The extra stuff on the end is because all the trig functions return their answers in radians, but the _rotation property works off of degrees, for some fool reason)

    Note that if you wanted to do this to "better missiles", you'd need to use dx/dy instead of vx/vy. (And if you wanted to do it to "many missiles", you'd need to use the arrays vxList and vyList)

    (Note that it's late, and I'm tired, and I havn't actually tested the code I just gave for rotation. It SHOULD work, but I havn't actually tried it. And I probably won't until tomorrow. Because it's late. and I'm tired. So there.)

  10. #10
    Unregistered User dnalogic's Avatar
    Join Date
    Feb 2001
    Location
    UK
    Posts
    146

    What about Balders Gate missiles?

    In Balders Gate, some of the enemies actually intersect your path in order to cut you off - it would be cool to have a missile that did that!

  11. #11
    Senior Member
    Join Date
    May 2001
    Posts
    425
    well that sounds really simple. I'll try the code. Thnks for the tutorial. this is gonna improve my game a lot.

    about the intersect missil. how would you do that? you would have to know the path that the player was taking.

    hehe.....psychic computers.....cool......haha

  12. #12
    Senior Member
    Join Date
    May 2001
    Posts
    425
    that code works. kinda......
    it does rotate the missile to point towards the target, but it only does it when it is launched, not in the air.
    i have a longer version of this type of code. im sure im wasting my time with it, but oh well. you can find it at :
    http://www.magikdesigns.com/Open%20S...tAngleDemo.fla
    it uses a function to call the angle between two MCs. Climber wrote it for me. It seems to work, but i am not sure how to incorperate it with the multi-missile system. you said in the comments that it was possible to make that code work within the missiles. could you make an example of that?


    sorry if i am being rude, but i am not as good with action script as you.
    [Edited by Anti-Matter0 on 07-17-2001 at 02:23 AM]

  13. #13
    Senior Member
    Join Date
    May 2001
    Posts
    425

    GOT IT!

    ok i know it makes the file a little bigger, but i got the angle function method to work.

    take your multi-missile example.
    in the first frame add this code
    Code:
    function getAngle (mc1, mc2) {
        mc1x = mc1._x;
        mc1y = mc1._y;
        mc2x = mc2._x;
        mc2y = mc2._y;
        if (mc1x<mc2x and mc1y<mc2y) {
            angle = Math.atan(Math.abs(mc1y-mc2y)/Math.abs(mc1x-mc2x))*(180/Math.PI);
            angle = angle+90;
        } else if (mc1x<mc2x and mc1y>mc2y) {
            angle = Math.atan(Math.abs(mc1y-mc2y)/Math.abs(mc1x-mc2x))*(180/Math.PI);
            angle = 90-angle;
        } else if (mc1x>mc2x and mc1y<mc2y) {
            angle = Math.atan(Math.abs(mc1x-mc2x)/Math.abs(mc1y-mc2y))*(180/Math.PI);
            angle = -(180-angle);
        } else if (mc1x>mc2x && mc1y>mc2y) {
            angle = Math.atan(Math.abs(mc1y-mc2y)/Math.abs(mc1x-mc2x))*(180/Math.PI);
            angle = -(90-angle);
        }
        return angle;
    }
    now in the second frame, the one that loops, add this code
    Code:
            eval("Missile"+i)._rotation = _root.getAngle(eval("Missile"+i), _root.target);
    they follow perfectly. i think the function just re calculates the angle in degrees, instead of converting from radians to degrees.

    but more importantly it works

  14. #14
    Coder-at-large
    Join Date
    May 2001
    Posts
    99

    Whoops

    you can tell it was late when I wrote that. I forgot how to convert between radians and degrees! (It should be divided by 180 instead of by 360)

    Also, I reversed dx and dy.

    Oh well, I warned you I was tired. :P


    The line of code I MENT to write was:
    Code:
    Missile._rotation=(Math.atan2(dy,dx)/Math.PI)*180;
    You can add it to "better missiles" as it is, or again, change dx,dy to vx,vy for the "cool missiles" code. (Also don't forget to change the missile to something that isn't circular, so you can tell where it is pointing. Make it so that it points to the right in the base movie clip.)

    I've uploaded an example .fla where I've already made these modifications. It's at http://www.cloudnet.com/~mathonwy/fl...ile_demo2.html for the completed movie, and http://www.cloudnet.com/~mathonwy/fl...sile_demo2.fla for the source code. (Yes, I know that the dumb missiles look (more) stupid now.)

    Good job on taking my confused, sleepy ramblings and making something that worked out of them, by the way.

  15. #15
    Senior Member
    Join Date
    May 2001
    Location
    Sweden
    Posts
    197
    Missile._rotation=(Math.atan2(dy,dx)/Math.PI)*180;
    Could you explain this? This is a totally new method for me. What is the , in the middle? sure you don't mean / ?

    I usually use something like:

    missile._rotation = Math.asin(diffY/r)*180/Math.PI;

    and add an if() to check the quadrant.

  16. #16
    Senior Member
    Join Date
    May 2001
    Posts
    425
    the html worked, they rotated, but the fla doesnt it is just ovals that dont rotate.

  17. #17
    Senior Member
    Join Date
    May 2001
    Posts
    425
    i have been foolin around with the multi-missiles. i added a gravity feature for a more realistic missile. basically, the rocket flies faster down than up. I also added a SAM Site to my game using your missiles. these are unique, because there is a small line that trails behind the missil. one thing i still dont quite get is how you are launching the missiles? i wish to make a manuel launcher for a special type of missile (dropped from AI plane)

    how would i go about making a function to launch specific, or random missiles?


    by the way. my file with the SAM Sites will be posted (open source) as soon as i figure this out.

  18. #18
    Coder-at-large
    Join Date
    May 2001
    Posts
    99

    Atan2 explanation:

    Originally posted by Rydeman
    Missile._rotation=(Math.atan2(dy,dx)/Math.PI)*180;
    Could you explain this? This is a totally new method for me. What is the , in the middle? sure you don't mean / ?

    I usually use something like:

    missile._rotation = Math.asin(diffY/r)*180/Math.PI;

    and add an if() to check the quadrant.
    It works sort of like this. (Warning, more math. :P )

    Good old trig. As we all know, there are various trig functions that have relations to the angle. In particular,

    Sin(angle) = dy/distance
    cos(angle) = dx/distance
    tan(angle) = dy/dx

    And as we also all know, the anti-trig fuctions, arcsin, arccos, and arctan, (usually abreviated as asin, acos, and atan) can reverse these operations, allowing us to solve for the angle:

    asin(dy/distance) = angle
    acos(dx/distance) = angle
    atan(dy/dx) = angle


    So if we wanted to solve for the angle, we could have used Math.atan(dy/dx). Unfortunately, this has problems (as anti-matter0 pointed out) when the angle is > 180.

    So what I did was just used Math.atan2. The way atan works is you give it a ratio. But either dx or dy can be negative. That's 2*2=4 possible combinations of positive/negative. but when we divide dy/dx, it ends up being one of two possibilities, positive or negative. So information is lost. (Which is why atan has problems with anything higher than 180 degrees)

    So eventually, some smart people started using something called Math.atan2, which instead of accepting the ratio between dx and dy, just accepts dx and dy as 2 seperate values. And so not only saves you the extra step of dividing them yourself, but also gives you better results.

    So THAT is why I used atan2, and what it is doing. Hope it helped.

  19. #19
    Senior Member
    Join Date
    May 2001
    Location
    Sweden
    Posts
    197
    Ohhh, so you mean atan2(@) is defined as "atan nr 2: improved version" instead of as I thought when reading it "atan(@)*atan(@)"?
    Wonderful! My thanks goes to those smartass ppl who invented it.

  20. #20
    Senior Member
    Join Date
    Apr 2001
    Posts
    190
    Great Tutorial.
    atan2.... my new found love....

    I think the Corkscrew Anti-Matter() was refering to is like an Anti-Archimedean spiral (No, I didn't memorize that, I'm not THAT nerdish ), I'm interested in making a missle that can do that.. with a lot shorter script of course ^_^. Anyways, it's formula for one is:
    r = a@
    where a is a constant, and @ is theta, the angle between the horizon and the radius. *What is this guy talking about?* I made a pic for you guys, I'll post it later ^_^

    anyways you can rearrange the terms to get
    @ = r/a;
    I also think that it's not going to be a perfect spiral.... so a should actually be a variable... I think that the velocity would do it. (remember velocity=sqrt(vx*vx+vy*vy)) and the radius, r, is equal to the distance between the two points (remember distance=sqrt(dx*dx+dy*dy)).

    So now you can do something to this effect. (Psuedo code... not sure if it's accurate)... Maybe someoen can clarify this stuff....

    Code:
    onClipEvent (load) {
    speed = 15;
    }
    onClipEvent (enterFrame) {
    dx=Target._x-Missile._x;
    dy=Target._y-Missile._y;
    distance=Math.sqrt((dx*dx)+(dy*dy));
    theta = distance/speed;
    _x -= Math.cos(theta);
    _y -= Math.sin(theta);
    }
    I'll try soem stuff out and update later.

    Lazily,
    Somar.



Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center

Poll by Flashkit.com