繁体   English   中英

2D: Moving Turret's Projectile Intercept 移动目标

[英]2D: Moving Turret's Projectile Intercept moving target

所以我正在制作太空游戏,宇宙飞船上有炮塔。

那些炮塔需要用恒定速度的弹丸射击移动目标。 AkA 它需要拦截并击中目标。

当我的船和 npc 船不在同一个方向或几乎同一个方向移动时,它工作得很好。 当他们向同一方向移动时,炮塔会在 npc 船的稍后方发射射弹。 但是一旦我转弯,它就会始终如一地击中 npc 船。

另外,当我站着不动时,npc 船在我面前微微开火,但当我站着不动时,我的船一直在撞击 npc 船。

这是我的代码:

Vector2 toTarget = (targetShip.GlobalPosition) - GlobalPosition;
            Vector2 targetVel = (targetShip.dir * targetShip.speed);
            Vector2 gunVelocity = (Player.currentShip.dir * Player.currentShip.playerSpeed);
            Vector2 vr = targetVel - gunVelocity;

            float t = AimAhead(toTarget, vr);

            if(t > 0f)
            {
                Vector2 aimPoint = targetShip.GlobalPosition + vr * t;
                dir = aimPoint - Player.currentShip.GlobalPosition; 
                GlobalRotation = Mathf.LerpAngle(GlobalRotation, dir.Angle(), turnRate * delta);
            }
            else
            {
                Vector2 aimPoint = targetShip.GlobalPosition;
                dir = aimPoint - Player.currentShip.GlobalPosition;
                GlobalRotation = Mathf.LerpAngle(GlobalRotation, dir.Angle(), turnRate * delta);
            }

前方目标 function:

 float a = vr.Dot(vr) - (projectile.speed * projectile.speed );
        float b = 2 * vr.Dot(toTarget);
        float c = toTarget.Dot(toTarget);

        float det = b * b - 4 * a * c;

        if (det > 0f)
        {
            return 2 * c / (Mathf.Sqrt(det) - b);
        }
        else
        {
            return -1f;
        }

对于简单的线性运动,这看起来是正确的:

float a = vr.Dot(vr) - (projectile.speed * projectile.speed);
float b = 2 * vr.Dot(toTarget);
float c = toTarget.Dot(toTarget);

从那里我会这样做:

var bb = b * b;
var a2 = 2 * a;
var ac4 = 4 * a * c;

并使用此检查:

if (bb >= ac4 && a2 != 0.0)

显然bb >= ac4等同于您正在使用的支票。

那么为什么a2.= 0.0 好吧,如果你猜对了前三行,我想你知道我们正在使用二次方程的解。 一个二次方程有两个解,分别是(-b + sqrt(bb - ac4))/a2(-b - sqrt(bb - ac4))/a2即二次方程的±:

二次公式

我不想被零除。

好的,所以我们有两种可能的解决方案。 这就是我进行的方式:

var r = Mathf.Sqrt(bb - ac4);
var times = new float[]{(-b + r)/a2, (-b - r)/a2};
var time = float.PositiveInfinity;
foreach (var candidate_time in times)
{
    if (candidate_time < 0.0)
    {
        continue;
    }

    if (candidate_time < time)
    {
        time = candidate_time;
    }
}

if (float.IsInfinity(time))
{
    return -1f;
}

return time;

这是基于击中移动目标的实现,该目标遵循您可以在其他地方找到的线段定义的路径。 对于这个简单的案例,我可以做更多的事情。

啊一个有趣的错误...

Vector2 aimPoint = targetShip.GlobalPosition + vr * t;

应该:

Vector2 aimPoint = targetShip.GlobalPosition + targetVel * t;

现在一切正常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM