gpt4 book ai didi

algorithm - Math.atan2 的寻的导弹问题

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:35:17 25 4
gpt4 key购买 nike

我正在为 Android 中的水平滚动太空射击游戏开发寻的导弹。我无法从我正在使用的算法中获得所需的行为。我希望导弹从玩家的船上水平射出,然后逐渐返回目标,如果弧度太大,则有机会错过目标。它有效,除非导弹未击中目标,在这种情况下,它通常会尝试遵循正弦波的路径,直到它跑出屏幕的右侧。我想要的是,导弹试图在其当前曲线(如典型的寻的导弹)中围绕目标保持盘旋,直到它击中 Sprite 或跑出屏幕边缘。我可能会添加一个限制,这样它就会爆炸并且不会一直在屏幕上旋转,但如果我让它工作的话,那将是以后添加的。

代码示例如下:

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 < 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();
}
}
}

归位算法发生在 Move() 中。我发现该问题的部分解决方案是添加此检查:

if (atanY >= 0 && atanX < 0)
atanY = -atanY;

在航向计算之前,但是如果从大于目标 Y 位置的 Y 位置发射导弹,导弹仍然会出错。

我已经和这个问题斗争了好几天了,我不太擅长三角函数,所以我希望有人能帮助我。我尽量不把问题与代码混为一谈,但如果需要更多代码或信息,我可以提供。

谢谢!

编辑

我改了行:

double atanX = target.Y + target.X - X;

到:

double atanX = target.X - X;

但是,如果导弹从大于目标 Y 位置的 Y 位置发射,它仍然会失灵。它朝目标俯冲,但如果未命中,它会突然弯曲起来,就好像它要进行一个环路。

最佳答案

问题可能是因为跨越了 360 度/0 度边界。

使用 h = 航向,即导弹行进的方向,t = 从导弹到目标的方向,f=0.1。现在考虑 t 与 h 顺时针旋转 20 度的情况。

如果 h = 180,则 t = 200 且 h(final) = 0.9*180+0.1*200 = 182,因此导弹按预期顺时针转动了少量。

但是如果 h = 350 那么 t = 370 = 10(根据 atan 公式),那么现在 h(final) = 0.9*350+0.1*10=316 并且导弹在错误的方向上转了很远的距离.

您需要添加一些逻辑来检查过零并避免此问题。

添加评论

好的 - atan 总是一个棘手的事情,因为 b = tan(a) 对范围内的任何 a 都是有效的 (-inf < a < + inf),但 a = atan(b) 总是会在某些范围内提供 b范围 (bmin <= b < bmin + 360),因此当矢量绕圆周旋转时,在某个点计算的角度会不连续,因为它上升超过 bmin + 360 并立即下降到 bmin 或下降低于 bmin 并突然跳升至 bmin + 360。如果我没有说清楚,那么只需考虑当时钟经过 12:59 pm 时会发生什么。它不会持续到 13:00(欧洲除外),而是回到凌晨 1:00。

Blackbear 的回答表明了正确的想法。我的等效“修复”是替换您的线路

  heading = (1 - f) * oldHeading + f * Math.atan2(atanY, atanX);

用类似的东西

  TheAngle = Math.atan2(atanY, atanX);
if Abs(TheAngle-oldheading) > 180 then
TheAngle = TheAngle - Sign(TheAngle)*360;
heading = (1 - f) * oldHeading + f * TheAngle;

其中 Sign(x) = +1 for x >=0 and -1 for x < 0

请注意,我的代码并非完全采用 C++、Java 或您正在使用的任何语言,因此您无法直接进行剪切和粘贴 - 但您应该能够将其转换为有用的东西。

关于algorithm - Math.atan2 的寻的导弹问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11892046/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com