4

I'm trying to create a homing missile in AS3. Easy enough when you want it to simply follow a point perfectly - but I'm trying to make the rocket have to turn around if the destination (target) bypasses it.

Here's what I've got - it almost works, but as you can see it's quite glitchy (particularly if the mouse is to the left of the rocket (seems to work OK if it's moving right).

http://projectavian.com/rocket.swf

Here's my Rocket class:

package
{
    import flash.display.Sprite;
    import flash.geom.Point;
    import flash.events.Event;

    public class Rocket extends Sprite
    {
        // vars
        public var target:Point;

        private const _vel:Number = 5;
        private const _steer:Number = Math.PI / 36;

        private var _destAng:Number = 0;
        private var _ang:Number = 0;
        private var _xv:Number = 0;
        private var _yv:Number = 0;

        /**
         * Constructor
         */
        public function Rocket()
        {
            // temp graphics
            graphics.lineStyle(2, 0);
            graphics.lineTo(26, 0);

            addEventListener(Event.ENTER_FRAME, _handle);
        }

        /**
         * Called on dispatch of Event.ENTER_FRAME
         */
        private function _handle(e:Event):void
        {
            _destAng = _getAng();

            _xv = Math.cos(_ang) * _vel;
            _yv = Math.sin(_ang) * _vel;

            x += _xv;
            y += _yv;

            if(_ang > _destAng) _ang -= _steer;
            if(_ang < _destAng) _ang += _steer;

            rotation = _ang * 180 / Math.PI;
        }

        /**
         * Get the angle to target
         */
        private function _getAng():Number
        {
            if(target)
            {
                var yp:Number = target.y - y;
                var xp:Number = target.x - x;

                return Math.atan2(yp, xp);
            }

            return 0;
        }
    }
}

I'm guessing this logic isn't catering for whatever is causing the missile to act strange moving left:

if(_ang > _destAng) _ang -= _steer;
if(_ang < _destAng) _ang += _steer;

Here is also the code I have used to create my Rocket, if it's helpful:

var point:Point = new Point();

var rocket:Rocket = new Rocket();
rocket.target = point;

addChild(rocket);

addEventListener(Event.ENTER_FRAME, _handle);
function _handle(e:Event):void
{
    point.x = mouseX;
    point.y = mouseY;
}
Marty
  • 39,033
  • 19
  • 93
  • 162
  • This might be naive, but why can't you do: new velocity/direction = velocity/direction to mouse coordination + old(velocity/direction) where velocity/direction is the vector that the missile is following, and the + is vector addition. – soandos May 12 '11 at 02:33
  • I'm confused - the point that the rocket is following is the mouse coordinate. So wouldn't those two things be the same? – Marty May 12 '11 at 02:38
  • Yes, but then I don't see why it matters if its going left or right, or forwards or backwards, it should be direction agnostic. I think it could be simpler, with just a current velocity property, current direction, and new velocity, new direction, and vector math. i am not sure your vector math is good btw... you can just add angles like that... – soandos May 12 '11 at 02:41
  • Hmm, my anything math ain't good to be honest. And hmm. Good thinking though I only vaguely understand how to implement that. – Marty May 12 '11 at 02:44
  • I think generally, your code is good (its not realistic, but should work none the less), but it might be running into errors with negative angles. try testing for if angle is negative, and if it is, add 2pi. – soandos May 12 '11 at 03:02

2 Answers2

3

This should work for you.

public class Rocket extends Sprite
{
    // vars
    public var target:Point;

    private const _vel:Number = 5;
    private const _steer:Number = Math.PI / 36;

    private var _destAng:Number = 0;
    private var _ang:Number = 0;
    private var _xv:Number = 0;
    private var _yv:Number = 0;

    public const SPEED:uint = 50;

    // TODO: get this from fixed timespet
    public const TIME_DELTA:Number = 0.05;
    public const RAD:Number = 57.2957795;
    public const DEG:Number = 0.0174532925;

    public function Rocket()
    {
        // temp graphics
        graphics.lineStyle(2, 0);

        // body should follow head
        graphics.moveTo(-26, 0);
        graphics.lineTo(0, 0);

        addEventListener(Event.ENTER_FRAME, _handle);
    }

    /**
     * Called on dispatch of Event.ENTER_FRAME
     */
    private function _handle(e:Event):void
    {
        var a:Number = _turnToFace(new Point(x, y), target, this.rotation * Math.PI / 180, 0.1);

        var dirX:Number = Math.cos(a);
        var dirY:Number = Math.sin(a);

        x += (dirX) * SPEED * TIME_DELTA;
        y += (dirY) * SPEED * TIME_DELTA;

        rotation = a * RAD;
    }

    private function _turnToFace(p:Point, f:Point, ca:Number, turnSpeed:Number):Number
    {           
        var xp:Number = f.x - p.x;
        var yp:Number = f.y - p.y;

        var desiredAngle:Number = Math.atan2(yp, xp);
        var difference:Number = _wrapAngle(desiredAngle - ca);

        difference = Math.max(-turnSpeed, Math.min(turnSpeed, difference));

        return _wrapAngle(ca + difference); 
    }

    private function _wrapAngle(radians:Number):Number
    {
        var pi2:Number = Math.PI * 2;

        while(radians < -Math.PI) radians += pi2;
        while(radians > Math.PI) radians -= pi2;

        return radians;
    }
}
Marty
  • 39,033
  • 19
  • 93
  • 162
62316e
  • 225
  • 2
  • 19
1

I found this code here

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;

With a little minor tweaking (calling the functions, basic things like that) it should be what you need.

soandos
  • 4,978
  • 13
  • 62
  • 96