0

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私の質問は、完全な放物線を作成するために速度 ( ) を失ったときに矢印を下に移動させるにはどうすればよいですか?

4

2 に答える 2

1

上記で説明したソリューションは、反復ごとに新しい速度を計算し、前の位置からのデルタ (変化) を計算して現在の位置を決定することに依存しています。

これは、ゲーム ループの通常のロジックに適合します。ただし、必要以上に計算が複雑であり、丸め誤差のために不安定になる可能性があります。

より簡単で安定した解決策は、放物線の方程式を決定し、これを使用して発射後の時間 t での位置を直接計算することです。

矢印が x=0、y=0 から始まるとします。発射速度を v とします。発射後の時間 t で、矢印の a 座標は x = kt です。ここで、k = v*cos(45) = v/sqrt(2) です。

y 位置は 2 次式 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 でこれら 2 つの方程式をまとめると、

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

v と t を知っていて、g を定義すると、この方程式から時間 t での x 座標と y 座標を直接計算できます。

これは、より単純なアプローチであり、より堅牢です (丸め誤差が蓄積されません)。私が個人的にやっている方法です。私の手榴弾は常に完璧な放物線の弧をたどり、計算効率の良い方法でそれを行います。

于 2013-06-29T06:02:55.950 に答える
0

注: 今まで XNA について聞いたことがありませんが、C# を使用しています。要点はそこにあるはずですが、これがうまくいかない場合はお知らせください。

最後の if ステートメントでは、Enter キーを離した後、Update を呼び出すたびに一定の (小さな定数) だけ下向きの速度を上げたいと考えています (y 座標を大きくすると、画面上で物事が「下」に移動すると仮定します)。 . double vy = timeHeld * Math.Sin(alpha)これを行うには、Enter が離されるとすぐに、毎回呼び出すのではなく、後で参照できるように結果を変数に保存し、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;
    }
}

もっと効率的な方法があるかもしれませんが、うまくいけばうまくいきます。これは物理サイトではありませんが、参照用にこれを参照してください ;-)

于 2013-06-26T21:09:42.433 に答える