【问题标题】:Create a parabolic trajectory with fixed angle创建具有固定角度的抛物线轨迹
【发布时间】:2013-06-26 18:59:50
【问题描述】:

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

我需要什么:

  • 您按住 Enter 的次数越多,箭头越强。
  • 箭头角度始终保持不变,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) 时落到底部以形成完美的抛物线?

【问题讨论】:

  • 提示:在地球上,抛出的物体往往会形成抛物线,因为重力引起的加速度会不断改变物体的y速度
  • 我明白了,所以你是在告诉我,我需要实现重力方法对吧?
  • 在尝试创建逼真的运动时使用重力通常是个好主意。
  • 如果它们总是以 45 度启动,你最好计算一次 math.sin(45 度) 和 math.cos(45 度) 并作为最终结果,例如 final double angular_component = 1 /math.sqrt(2d)

标签: c# algorithm xna game-physics projectile


【解决方案1】:

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

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

更简单更稳定的解决方案是确定抛物线方程,并以此直接计算发射后t时刻的位置。

让箭头从 x=0,y=0 开始。设发射速度为v。发射后t时刻箭头的a坐标为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 坐标。

这是一种更直接且更稳健的方法(舍入误差不会累积)。这是我个人的做法。我的手榴弹总是遵循完美的抛物线弧线,并且以一种计算效率高的方式进行。

【讨论】:

    【解决方案2】:

    注意:直到现在我才听说过 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 以供参考;-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-25
      • 2016-10-28
      • 2018-04-15
      • 2012-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多