创建一个固定角度的抛物线轨迹

时间:2013-06-26 18:59:51

标签: c# algorithm xna game-physics projectile

我正试图在我的XNA游戏中投掷箭头,但我很难想要实现一个好的抛物线。

我需要什么:

  • 你持的越多输入箭头越强。
  • 箭头角度始终相同, 45度

这就是我已经拥有的:

private float velocityHeld = 1f;
protected override void Update(GameTime gameTime)
{

    if (Keyboard.GetState().IsKeyDown(Keys.Enter) && !released)
    {
        timeHeld += velocityHeld;
        holding = true;
    }
    else
    {
        if (holding)
        {
            released = true;
            holding = false;
            lastTimeHeld = timeHeld;
        }
    }


    if (released && timeHeld > 0)
    {
        float alpha = MathHelper.ToRadians(45f);
        double vy = timeHeld * Math.Sin(alpha);
        double vx = timeHeld * Math.Cos(alpha);

        ShadowPosition.Y -= (int)vy;
        ShadowPosition.X += (int)vx;
        timeHeld -= velocityHeld;
    }
    else
    {
        released = false;
    }
}

我的问题是,当箭头失去速度(timeHeld)以制作完美的抛物线时,我需要做些什么才能让箭头走到尽头?

2 个答案:

答案 0 :(得分:0)

注意:我从未听说过XNA,但我确实使用过C#。让我知道如果这不起作用,虽然它的要点应该在那里。

在你的最后一个if语句中,在释放Enter键之后,你想要在每次调用Update时将向下速度增加一定的(小常数)量(我假设增加y坐标使得事情向下移动“在屏幕上)。要做到这一点,只要Enter被释放,而不是每次都调用double vy = timeHeld * Math.Sin(alpha),将结果保存到稍后可以引用的变量中,然后使用bool值来跟踪何时计算该值,这是仅在Enter发布后立即。

换句话说,它是这样的:

// extra variables
bool justReleased = false;
double vy, vx;
...
protected override void Update(GameTime gameTime)
{
    // ...
        if (holding)
        {
            released = true;
            holding = false;
            lastTimeHeld = timeHeld;
            justReleased = true; // add this here
        }
    // ...

    if (released && timeHeld > 0)
    {
        float alpha = MathHelper.ToRadians(45f);

        // not local variables anymore. Also I flipped the sign - my intention is that initial vertical velocity is "upwards"
        if(justReleased)
        {
            vy = -1 * timeHeld * Math.Sin(alpha); 
            vx = timeHeld * Math.Cos(alpha);
            justReleased = false;
        }

        ShadowPosition.Y += (int)vy; // Note: I flipped this operator
        ShadowPosition.X += (int)vx;
        timeHeld -= velocityHeld;

        // increase the downward velocity
        vy += 2; // or some constant. I can't test this. :\
    }
    else
    {
        released = false;
    }
}

希望这有效,尽管可能有更有效的方法来实现这一点。虽然这不是物理站点,但请参阅this以供参考; - )

答案 1 :(得分:0)

上面讨论的解决方案依赖于您在每次迭代时计算新的速度,然后计算前一个位置的增量(变化)以确定当前位置。

这符合游戏循环的正常逻辑。然而,它在计算上比它需要的更复杂,并且由于舍入误差而可能不稳定。

更简单,更稳定的解决方案是确定抛物线的方程,并使用它在发射后的时间t直接计算出位置。

让箭头从x = 0开始,y = 0。让发射速度为v。在发射后的时间t,箭头的坐标为x = kt,其中k = v * cos(45)= v / sqrt(2)。

y位置是二次方,y = at ^ 2 + bt + c,我们不知道a,b,c。

但是当t = 0时,y = 0,所以c = 0

当t = 0时,初始向下速度为v * sin(45)= v / sqrt(2)

使用微小的微积分(区分位置以获得速度),t = 0

v / sqrt(2)= 2at + b = b

区分速度以获得加速度,我们得到t = 0时的初始加速度为2a。但唯一的加速是由于重力引起的,所以2a = -g其中g是你的引力常数。

在时间t

将这两个方程放在一起

x(t)= v / sqrt(2); y(t)= - (g / 2)t ^ 2 + vt / sqrt(2)

你知道v和t,你定义g,所以你可以直接从这个方程计算出时间t的x和y坐标。

这是一种更直接的方法,更强大(舍入错误不会累积)。这就是我亲自做的事情。我的手榴弹始终遵循完美的抛物线弧,并以计算效率的方式进行。