7

私の質問は、2D の 2 つのベクトル間の最小角度の方向を計算することに関するものです。私は C++ でゲームを作成しています。障害の 1 つは熱を求めるミサイルランチャーです。ターゲットと弾丸の間のベクトルを計算し、ベクトルを正規化し、速度を掛けることで機能させます。しかし、私は今、このクラスをより良くするために戻ってきています。プレーヤーを即座にロックするのではなく、弾丸ベクトルが特定の角度 (弾丸ベクトルとベクトル bulletloc->target の間の角度) 内にある場合にのみロックするようにしたいと考えています。それ以外の場合は、ターゲットに向かってゆっくりとパンして、プレーヤーがそれを回避するのに十分なスペースを確保するようにします。私はこれをすべて行いました(vb.netプロジェクトで、問題を単純化し、解決してからC ++で書き直すことができました)。ただし、最速のルートが反時計回りであっても、弾丸は常にターゲットに向かって時計回りに回転します。したがって、問題は、最小角度がカバーされるように回転を適用する方向を考え出すことです。これが私のコードです。私が説明していることを試してみてください。

    Function Rotate(ByVal a As Double, ByVal tp As Point, ByVal cp As Point, ByVal cv As Point)
    'params a = angle, tp = target point, cp = current point, cv = current vector of bullet'
    Dim dir As RotDir 'direction to turn in'
    Dim tv As Point 'target vector cp->tp'
    Dim d As Point 'destination point (d) = cp + vector'
    Dim normal As Point
    Dim x1 As Double
    Dim y1 As Double
    Dim VeritcleResolution As Integer = 600

    tp.Y = VeritcleResolution - tp.Y 'modify y parts to exist in plane with origin (0,0) in bottom left'
    cp.Y = VeritcleResolution - cp.Y
    cv.Y = cv.Y * -1

    tv.X = tp.X - cp.X 'work out cp -> tp'
    tv.Y = tp.Y - cp.Y

    'calculate angle between vertor to target and vecrot currntly engaed on'
    Dim tempx As Double
    Dim tempy As Double

    tempx = cv.X * tv.X
    tempy = cv.Y * tv.Y

    Dim DotProduct As Double

    DotProduct = tempx + tempy 'dot product of cp-> d and cp -> tp'

    Dim magCV As Double 'magnitude of current vector'
    Dim magTV As Double 'magnitude of target vector'

    magCV = Math.Sqrt(Math.Pow(cv.X, 2) + Math.Pow(cv.Y, 2))
    magTV = Math.Sqrt(Math.Pow(tv.X, 2) + Math.Pow(tv.Y, 2))

    Dim VectorAngle As Double

    VectorAngle = Acos(DotProduct / (magCV * magTV))
    VectorAngle = VectorAngle * 180 / PI 'angle between cp->d and cp->tp'

    If VectorAngle < a Then 'if the angle is small enough translate directly towards target'
        cv = New Point(tp.X - cp.X, tp.Y - cp.Y)
        magCV = Math.Sqrt((cv.X ^ 2) + (cv.Y ^ 2))

        If magCV = 0 Then
            x1 = 0
            y1 = 0
        Else
            x1 = cv.X / magCV
            y1 = cv.Y / magCV
        End If

        normal = New Point(x1 * 35, y1 * 35)
        normal.Y = normal.Y * -1

        cv = normal
    ElseIf VectorAngle > a Then 'otherwise smootly translate towards the target'
        Dim x As Single
        d = New Point(cp.X + cv.X, cp.Y + cv.Y)


        a = (a * -1) * PI / 180 'THIS LINE CONTROL DIRECTION a = (a*-1) * PI / 180 would make the rotation counter clockwise'

        'rotate the point'
        d.X -= cp.X
        d.Y -= cp.Y

        d.X = (d.X * Cos(a)) - (d.Y * Sin(a))
        d.Y = (d.X * Sin(a)) + (d.Y * Cos(a))

        d.X += cp.X
        d.Y += cp.Y

        cv.X = d.X - cp.X
        cv.Y = d.Y - cp.Y

        cv.Y = cv.Y * -1
    End If

    Return cv

End Function

私が持っていた 1 つのアイデアは、2 つのベクトルの方位を計算することでした。差が 180 度より大きい場合は時計回りに回転し、それ以外の場合は反時計回りに回転します。ありがとう。

編集: このサイトは非常に役立つことを付け加えたいと思います。自分の問題を解決するために、他の人からの質問をよく利用します。この機会に感謝の言葉を述べたいと思います。

4

2 に答える 2

11

コードに記述したように、2 つの (正規化された) ベクトル間の角度は、内積の逆余弦です。

符号付きの角度を取得するには、他の 2 つのベクトルが存在する平面の法線を表す 3 番目のベクトルを使用できます。2D の場合、これは、(0, 0, 1)。

次に、最初のベクトル (角度を相対的にしたいもの) と 2 番目のベクトルの外積をとります (外積は可換ではないことに注意してください)。角度の符号は、結果のベクトルと平面法線の間の内積の符号と同じでなければなりません。

コード内 (C#、申し訳ありません) -- すべてのベクトルが正規化されていると想定されていることに注意してください。

public static double AngleTo(this Vector3 source, Vector3 dest)
{
    if (source == dest) {
        return 0;
    }
    double dot; Vector3.Dot(ref source, ref dest, out dot);
    return Math.Acos(dot);
}

public static double SignedAngleTo(this Vector3 source, Vector3 dest, Vector3 planeNormal)
{
    var angle = source.AngleTo(dest);
    Vector3 cross; Vector3.Cross(ref source, ref dest, out cross);
    double dot; Vector3.Dot(ref cross, ref planeNormal, out dot);
    return dot < 0 ? -angle : angle;
}

これは、2 つのベクトル間の外積が、最初の 2 つのベクトルによって定義された平面に対して垂直 (垂直) な 3 番目のベクトルを生成するという事実を利用して機能します (つまり、本質的に 3D 操作です)。a x b=であるため、ベクトルは常に平面に対して垂直になりますが、 と の間の-(b x a)(符号付き) 角度に応じて別の側になります (右手の法則と呼ばれるものがあります)。ab

したがって、外積は、ベクトル間の角度が 180° を通過するときに方向を変える、平面に垂直な符号付きベクトルを提供します。真上を向いている平面に垂直なベクトルが事前にわかっている場合、内積の符号を確認することで、外積がその平面の法線と同じ方向にあるかどうかを判断できます。

于 2012-06-13T20:13:07.077 に答える