0

私のゲームには、プレイヤーの発射物がプレイエリアの壁に当たって跳ね返るパワーアップがあります。私はそれを機能させることができないようです、ゲームの境界は通常通り水平と垂直です。

現在、私のコードはこれです。

public void UpdatePlasma()
{
    Direction = new Vector2((float)Math.Cos(Angle), (float)Math.Sin(Angle));
    //Vector2 Velocity = new Vector2(1, 1);
    Position += Direction * projSpeed;

    if ((Position.X >= viewport.Width) || (Position.X <= 0))
    {
        Angle = -Angle;
    }

    else if ((Position.Y >= viewport.Height) || (Position.Y <= 0))
    {
        Angle = -Angle;
    }
}

この種の作品。発射物は時々上下の境界で跳ね返り(これは角度が0になるためである可能性があるため、否定されて通過するときに方向が変わらないため)、左右の境界ではまったく跳ね返りません。次に、コメントアウトされた速度ベクトルを自分の位置に掛けて、X座標またはY座標のいずれかを否定しようとしましたが、これはまったく機能しませんでした。

4

1 に答える 1

4

反時計回りのラジアン(正) 時計回りのラジアン(負)

これらの図は、円の周りを時計回りまたは反時計回りに移動するときのラジアン角度を示しています。あなたのゲームでは、赤い矢印の方向は、特定の角度(つまり、0ラジアンが正しい、PI / 2ラジアンが上など)が与えられた場合のボールの動きと同等であると想定しています。

これらの図を参考にして、ボールが壁に当たる4つのケースを考えてみましょう。上、右、下、左に移動するときは、それぞれ上、右、下、左です。

最初に、現在のコードを使用してケースを調べ、誤った動作が発生している理由を説明します。「入射角」とは、ボールが(それぞれの壁と)衝突する前の角度であり、「たわみ角」とは、ボールが衝突した後の角度です。


使用するdeflected_angle = -incidence_angle

ケース1:ボールが上に移動し、上壁に当たる:

incidence_angle = PI/2 = up
deflected_angle = -PI/2 = 3PI/2 = down

良い!

ケース2:ボールが下に移動し、下の壁にぶつかる:

incidence_angle = 3PI/2 = down
deflected_angle = -3PI/2 = up

良い!

ケース3:ボールが右に移動し、右の壁に当たる:

incidence_angle = 0 = right
deflected_angle = -0 = 0 = right

おっと!

ケース4:ボールが左に移動し、左の壁に当たる:

incidence_angle = PI = left
deflected_angle = -PI = PI = left

おっと!


現在のコードが正しく動作している場合とそうでない場合がある理由を理解したので、いくつかの解決策を考え出す必要があります。単に角度を否定することに関心がないことは明らかです。むしろ(少なくとも4つのサンプルケースでは)、ボールを反対方向に偏向させたいと考えています。これを行うには、PIを角度に追加します。これは半円の回転です。

それでは、新しい方程式を使ってケースを見ていきましょう。


使用するdeflected_angle = incidence_angle + PI

ケース1:ボールが上に移動し、上壁に当たる:

incidence_angle = PI/2 = up
deflected_angle = PI/2 + PI = 3PI/2 = down

良い!

ケース2:ボールが下に移動し、下の壁にぶつかる:

incidence_angle = 3PI/2 = down
deflected_angle = 3PI/2 + PI = 5PI/2 = PI/2 = up

良い!(これ5PI/2により、円の周りを完全に周回し、次にいくつかの周回を行うことに注意してください。を計算することで同じ角度を得ることができます。5PI/2 - 2PIこれはPI/2です。)

ケース3:ボールが右に移動し、右の壁に当たる:

incidence_angle = 0 = right
deflected_angle = 0 + PI = PI = left

良い!

ケース4:ボールが左に移動し、左の壁に当たる:

incidence_angle = PI = left
deflected_angle = PI + PI = 2PI = 0 = right

良い!


このソリューションを試して、結果を観察することをお勧めします。ボールが考慮している4つ以外の角度で側面に当たった場合でも、奇妙な動作を観察する必要があります(特に、物理的に予想されるように偏向するのではなく、ボールが来た方向に向かって跳ね返ります)。

これを修正するには、垂直の壁(左または右)に当たったときのたわみ角度をとして計算deflected_angle = PI - incident_angleし、水平の壁(上または下)に当たったときの角度をとして計算しdeflected_angle = 2PI - incident_angleます。

これが当てはまる理由を次の図に示します。簡潔にするために、ボールが上壁に当たった場合のみを見ていきます。他の場合も同様に示されています。

赤いベクトルは入射角を示し、青いベクトルは偏向角を示します。各ベクトルは2回表示され、翻訳されただけで、意味は変わりません(唯一の目的は図を明確にすることです)。また、角度は円弧、、、およびとして追加で示されていますABつまりC、赤のベクトルとA、および青のベクトルCは同じものを表しています)。

たわみの例(垂直法線)

C = PI + Bこの図から、とを導き出すことができますB = PI - A。これらを組み合わせて、最終的な方程式に到達します。C(これが偏向角であり、入射角であることに注意してくださいA)。

let:
C = PI + B
B = PI - A

then:
C = PI + (PI - A)
C = PI + PI - A
C = 2PI - A

note:
2PI = 0
therefore, C = -A
(this is why the top and bottom cases worked)

therefore:
deflected_angle = 2PI - incidence_angle

繰り返しますが、同様の方法で他のケースをチェックして、残りの方程式にたどり着くことができます。deflected_angle = PI - incident_angle下を打つボールは上を打つのと同じ方程式で解かれ、方程式は左右で同じであることがわかります。

さらに読みたい場合は、ボールを任意の線からそらすことができます(つまり、水平または垂直だけではありません)。これは、偏向しているサーフェスの法線を観察することで実行できます。リストや特定のリンクは壊れてしまう可能性があるため、控えさせていただきます。代わりに、私はいくつかのグーグルをお勧めします(彼らはおそらくしばらくの間存在するでしょう;))。


追加の考慮事項

ゲーム物理学で対処しなければならないもう1つの問題は、少なくとも個別の物理学を使用する場合(衝突が発生する前に衝突時間を決定しようとする連続的なアプローチとは対照的に)、オブジェクトが互いに侵入することです。これに関する問題を理解するために、ボールが複数の更新サイクルの間境界の外にとどまった場合に何が起こるかを検討してください(更新頻度、ボール速度、ボール加速度、および衝突解像度によっては、可能性がある場合とない場合があります)。 。最初の更新サイクルで、ボールが境界より上にあることを検出したとすると、たわみ角度を正しく計算し、それをボールの新しい角度として設定します。ここで、2番目の更新サイクルで、この角度に従ってボールを移動しますが、ボールはまだ境界より上にあります(つまり、境界に再び入る速度と加速度を考えると、十分に移動しませんでした。あなたのコードは再びボールが境界を超えていることを検出し、ボールを上向きに偏向させます!その結果、ボールが壁に短時間引っかかったり、壁に永久に引っかかったり、競技場から完全に離れたりします。この特定の質問トピックの範囲外であるこの問題に対抗する多くの方法があります。

欠落しているケースも1つあります(実際には4つですが、すべて同じ考えです):ボールがフィールドの隅を横切った場合はどうなりますか?ボールを単一の壁に当たったものとしてのみ扱うと、たわみ角度が正しくなくなり、ボールが境界から飛び出します。したがって、この可能性を説明するために追加のロジックが必要になります。

于 2012-10-28T21:02:46.047 に答える