Note that there are some explanatory texts on larger screens.

plurals
  1. POHoming missile trouble with Math.atan2
    text
    copied!<p>I'm working on a homing missile for a horizontal-scrolling, space-shooter game in android. I'm having trouble getting the desired behavior from the algorithm I'm using. I would like for the missile to shoot out horizontally from the player's ship and then gradually home in on the target, with a chance to miss the target if the arc is too great. It works, except if the missile misses the target, in which case, it generally attempts to follow the path of a sine wave, until it runs off the right side of the screen. What I would like, is for the missile to attempt to keep circling around the target in its current curve (like the stereotypical homing missile) until it hits a sprite or runs off the edge of the screen. I may add a limit so that it will explode and not keep spinning around on the screen, but that would be a later addition if I get this working.</p> <p>Here's an example of the code:</p> <pre><code>public class HomingMissile extends Shot { Bitmap bitmap; Rect sourceRect; Rect destRect; private double heading; private Sprite target; private int frameNumber; private int currentFrame; private int frameDelta; public HomingMissile(Context context, ImageLoader imageLoader, int x, int y, int minX, int minY, int maxX, int maxY, int dx, int dy) { super(context, imageLoader, x, y, minX, minY, maxX, maxY, dx, dy); heading = 0; frameNumber = 3; currentFrame = 0; frameDelta = 1; target = new Sprite(context, imageLoader, 300, 50, minX, minY, maxX, maxY, 0, 0); } @Override public void setBitmap(int id) { bitmap = imageLoader.GetBitmap(id); width = bitmap.getWidth(); height = bitmap.getHeight() / frameNumber; sourceRect = new Rect(0, 0, width - 1, height); destRect = new Rect(X, Y, X + width - 1, Y + height - 1); } public void setTarget(Sprite sprite) { target = sprite; } @Override public void Move() { if (!visible) return; final double f = 0.03; double oldHeading = heading; double atanY = target.Y + (target.height / 2) - Y; double atanX = target.Y + target.X - X; heading = (1 - f) * oldHeading + f * Math.atan2(atanY, atanX); X += Math.cos(heading) * 10; Y += Math.sin(heading) * 10; UpdateBounds(); if (currentFrame == frameNumber - 1) frameDelta = -frameDelta; if (currentFrame &lt; 0) { frameDelta = -frameDelta; currentFrame += frameDelta; } sourceRect.top = height * currentFrame; sourceRect.bottom = sourceRect.top + height; currentFrame += frameDelta; if (target.Collide(destRect, bitmap)) { visible = false; heading = 0; } if (OutOfBounds()) { visible = false; heading = 0; } } @Override public void Draw(Canvas canvas) { if (visible) { canvas.save(); canvas.rotate((float) (heading * 180 / Math.PI) * 1.5f, X + width / 2, Y + height / 2); canvas.drawBitmap(bitmap, sourceRect, destRect, paint); canvas.restore(); } } } </code></pre> <p>The homing algorithm occurs in Move(). A partial solution I found to the problem was to add this check:</p> <pre><code>if (atanY &gt;= 0 &amp;&amp; atanX &lt; 0) atanY = -atanY; </code></pre> <p>before the heading calculation, but the missile still bugs out if it is fired from a Y position greater than the target's Y position.</p> <p>I've been battling with this for several days now, and I'm not very good with trig, so I'm hoping someone can help me. I tried not to clutter up the question with code, but if anymore code or information is needed, I can provide it.</p> <p>Thanks!</p> <h2>EDIT</h2> <p>I changed the line:</p> <pre><code>double atanX = target.Y + target.X - X; </code></pre> <p>to:</p> <pre><code>double atanX = target.X - X; </code></pre> <p>but, if the missile is fired from a Y position greater than the target's Y position, it still bugs out. It dives toward the target, but if it misses, it abruptly curves up as if it were going to do a loop-de-loop.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload