简体   繁体   English

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

[英]Create a parabolic trajectory with fixed angle

I'm trying to throw an arrow in my XNA game, but I'm having a hard time trying to realize a good parabola. 我正在尝试在XNA游戏中投箭,但是我很难尝试实现一个好的抛物线。

What I need: 我需要的:

  • The more you hold Enter stronger the arrow goes. 你越握输入更强的箭头去。
  • The arrow angle will be always the same, 45 degrees . 箭头角度将始终相同,为45度

This is what I have already have: 这是我已经拥有的:

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

My question is, what do I need to do to make the arrow to go bottom as it loses velocity ( timeHeld ) to make a perfect parabola? 我的问题是,当箭头失去速度( timeHeld )以制作出完美的抛物线时,我该怎么做才能使其箭头走到底?

Note: I never heard of XNA until now, but I do use C#. 注意:到目前为止,我从未听说过XNA,但我确实使用C#。 Let me know if this doesn't quite work, though the gist of it should be there. 让我知道这是否行得通,尽管它的要旨应该在那里。

In your last if-statement, after Enter key is released, you want to increase the downward velocity by a certain (small constant) amount every time you call Update (I assume increasing the y-coordinate makes things move "down" on screen). 在您的最后一个if语句中,松开Enter键后,您希望每次调用Update时都将向下速度增加一定的(小常数)(我假设增加y坐标会使事物在屏幕上“向下”移动) 。 To do this, as soon as Enter is released, instead of calling double vy = timeHeld * Math.Sin(alpha) every time, save the result into a variable you can reference later, then use a bool value to keep track of when to calculate that value, which is ONLY right after Enter is released. 为此,请在释放Enter后立即进行操作,而不是每次都调用double vy = timeHeld * Math.Sin(alpha) ,将结果保存到以后可以引用的变量中,然后使用bool值来跟踪何时计算该值,只有在释放Enter之后才可以。

In other words, it goes something like this: 换句话说,它是这样的:

// 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;
    }
}

Hopefully this works, though there might be more efficient ways to do this. 希望这可以奏效,尽管可能会有更有效的方法来做到这一点。 Though this isn't a physics site, see this for reference ;-) 虽然这不是一个物理站点,请参见参考;-)

The solutions discussed above rely on you calculating a new velocity on every iteration, and then calculating the delta (change) from the previous position to determine the current position. 上面讨论的解决方案依赖于您在每次迭代中计算新的速度,然后计算前一位置的增量(变化)以确定当前位置。

This fits in with the normal logic of a game loop. 这符合游戏循环的正常逻辑。 It is however computationally more complex than it needs to be, and is possibly unstable due to rounding errors. 但是,它在计算上比需要的更为复杂,并且可能由于舍入误差而变得不稳定。

The simpler and more stable solution is to determine the equation for the parabola and use this to directly work out the position at time t after launch. 更简单,更稳定的解决方案是确定抛物线方程,并用其直接计算发射后时刻t的位置。

Let the arrow start at x=0, y=0. 让箭头从x = 0,y = 0开始。 Let the launch velocity be v. At time t after launch the a coordinate of the arrow is x = kt, where k = v*cos(45) = v/sqrt(2). 假设发射速度为v。在发射后的时间t,箭头的坐标为x = kt,其中k = v * cos(45)= v / sqrt(2)。

The y position is a quadratic, y = at^2 + bt + c where we don't know a, b, c. y位置是二次的,y = at ^ 2 + bt + c,我们不知道a,b,c。

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

When t=0, the initial downward velocity is v*sin(45) = v/sqrt(2) 当t = 0时,初始向下速度为v * sin(45)= v / sqrt(2)

Using a tiny bit of calculus (differentiating position to get velocity), at t=0 在t = 0时使用微积分(求位置的微分)

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

Differentiating velocity to get acceleration, we get the initial acceleration at t=0 is 2a. 通过微分速度获得加速度,我们得到t = 0时的初始加速度为2a。 But the only acceleration is due to gravity, so 2a=-g where g is your gravitational constant. 但是唯一的加速度是由于重力引起的,所以2a = -g,其中g是您的重力常数。

Putting these two equations together, at time t 在时间t将这两个方程放在一起

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

You know v and t, you define g, so you can work out the x and y co-ordinates at time t directly from this equation. 您知道v和t,定义了g,因此可以直接从该方程式计算出在时间t处的x和y坐标。

This is a more straightforward approach and more robust (rounding errors will not accumulate). 这是一种更直接,更可靠的方法(舍入误差不会累积)。 It is how I personally do it. 这就是我个人的方式。 My hand grenades always follow perfect parabolic arcs, and do so in a computationally efficient manner. 我的手榴弹始终遵循完美的抛物线弧,并且以计算有效的方式进行。

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

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