5

私は新しいゲームに取り組んでおり、スロープの座標に対する座標に基づいて、プレイヤー (スロープ上) が特定のメッシュと衝突しているかどうかを検出しようとしています。この関数を使用していますが、機能していないようです (傾きが小さすぎるか何かのようです)。

//Slopes



        float slopeY = max.Y-min.Y;

    float slopeZ = max.Z-min.Z;

    float slopeX = max.X-min.X;

    float angle = (float)Math.Atan(slopeZ/slopeY);

    //Console.WriteLine(OpenTK.Math.Functions.RadiansToDegrees((float)Math.Atan(slopeZ/slopeY)).ToString()+" degrees incline");



    slopeY = slopeY/slopeZ;

    float slopeZX = slopeY/slopeX;

    //End slopes

    float surfaceposX = max.X-coord.X;

    float surfaceposY = max.Y-coord.Y;

    float surfaceposZ = min.Z-coord.Z;



    min-=sval;

    max+=sval;

    //Surface coords



    //End surface coords



    //Y SHOULD = mx+b, where M = slope and X = surfacepos, and B = surfaceposZ



    if(coord.X<max.X& coord.X>min.X&coord.Y>min.Y&coord.Y<max.Y&coord.Z>min.Z&coord.Z<max.Z) {







        if(slopeY !=0) {

        Console.WriteLine("Slope = "+slopeY.ToString()+"SlopeZX="+slopeZX.ToString()+" surfaceposZ="+surfaceposZ.ToString());

            Console.WriteLine(surfaceposY-(surfaceposY*slopeY));



            //System.Threading.Thread.Sleep(40000);



        if(surfaceposY-(surfaceposZ*slopeY)<3 || surfaceposY-(surfaceposX*slopeZX)<3) {

        return true;

        } else {

        return false;

        }

        } else {

        return true;

        }



    } else {





    return false;

    }

助言がありますか?

出力例:

59.86697
6.225558 2761.331
68.3019 度の傾斜
59.86698,46.12445
59.86698
6.225558 2761.332
0 度の傾斜


下に行ってはいけない ランプ


編集:問題を部分的に修正しました。傾斜検出は機能しますが、壁を通り抜けられるようになりました???

//Slopes



        float slopeY = max.Y-min.Y;

    float slopeZ = max.Z-min.Z;

    float slopeX = max.X-min.X;

    float angle = (float)Math.Atan(slopeZ/slopeY);

    //Console.WriteLine(OpenTK.Math.Functions.RadiansToDegrees((float)Math.Atan(slopeZ/slopeY)).ToString()+" degrees incline");



    slopeY = slopeY/slopeZ;

    float slopey = slopeY+1/slopeZ;

    float slopeZX = slopeY/slopeX;

    //End slopes

    float surfaceposX = min.X-coord.X;

    float surfaceposY = max.Y-coord.Y;

    float surfaceposZ = min.Z-coord.Z;



    min-=sval;

    max+=sval;

    //Surface coords



    //End surface coords



    //Y SHOULD = mx+b, where M = slope and X = surfacepos, and B = surfaceposZ



    if(coord.X<max.X& coord.X>min.X&coord.Y>min.Y&coord.Y<max.Y&coord.Z>min.Z&coord.Z<max.Z) {







        if(slopeY !=0) {

        Console.WriteLine("Slope = "+slopeY.ToString()+"SlopeZX="+slopeZX.ToString()+" surfaceposZ="+surfaceposZ.ToString());

            Console.WriteLine(surfaceposY-(surfaceposY*slopeY));



            //System.Threading.Thread.Sleep(40000);

         surfaceposZ = Math.Abs(surfaceposZ);



        if(surfaceposY>(surfaceposZ*slopeY) & surfaceposY-2<(surfaceposZ*slopeY) || surfaceposY>(surfaceposX*slopeZX) & surfaceposY-2<(surfaceposX*slopeZX)) {

        return true;

        } else {

        return false;

        }

        } else {

        return true;

        }



    } else {





    return false;

    }
4

1 に答える 1

2

BSP ツリーの実装を検討したことがありますか? 現在使用しているコードでバグを解決したとしても、まともなサイズ/複雑さのメッシュでは非常に遅くなります。BSP またはクワッドツリーは、コードの簡素化とパフォーマンスの向上に大いに役立ち、実装も非常に簡単です。

編集

これは、優れた BSP チュートリアルと概要へのリンクです。

地形のみに関心がある (垂直の壁やドアなどがない) 場合は、四分木の方が適している可能性があります。

これは、gamedev.net の素敵な四分木のチュートリアルです。

これらのアルゴリズムは両方とも、検索を容易にするためにジオメトリをツリーに分割することを目的としています。あなたの場合、衝突の目的でポリゴンを検​​索しています。BSP ツリーを構築するには (非常に簡単に):

ツリー内のノードの構造を定義します。

public class BspNode
{
    public List<Vector3> Vertices { get; set; }

    // plane equation coefficients
    float A, B, C, D;

    BspNode front;
    BspNode back;

    public BspNode(Vector3 v1, Vector3 v2, Vector3 v3)
    {
        Vertices = new List<Vector3>();
        Vertices.AddRange(new[] { v1, v2, v3 });
        GeneratePlaneEquationCoefficients();
    }

    void GeneratePlaneEquationCoefficients()
    {

        // derive the plane equation coefficients A,B,C,D from the input vertex list.
    }

    bool IsInFront(Vector3 point)
    {
        bool pointIsInFront=true;
        // substitute point.x/y/z into the plane equation and compare the result to D
        // to determine if the point is in front of or behind the partition plane.
        if (pointIsInFront && front!=null)
        {
            // POINT is in front of this node's plane, so check it against the front list.
            pointIsInFront = front.IsInFront(point);
        }
        else if (!pointIsInFront && back != null)
        {
            // POINT is behind this plane, so check it against the back list.
            pointIsInFront = back.IsInFront(point);
        }
        /// either POINT is in front and there are no front children,
        /// or POINT is in back and there are no back children. 
        /// Either way, recursion terminates here.
        return pointIsInFront;            
    }

    /// <summary>
    /// determines if the line segment defined by v1 and v2 intersects any geometry in the tree.
    /// </summary>
    /// <param name="v1">vertex that defines the start of the ray</param>
    /// <param name="v2">vertex that defines the end of the ray</param>
    /// <returns>true if the ray collides with the mesh</returns>
    bool SplitsRay(Vector3 v1, Vector3 v2)
    {

        var v1IsInFront = IsInFront(v1);
        var v2IsInFront = IsInFront(v2);
        var result = v1IsInFront!=v2IsInFront;

        if (!result)
        {
            /// both vertices are on the same side of the plane,
            /// so this node doesn't split anything. Check it's children.
            if (v1IsInFront && front != null)
                result =  front.SplitsRay(v1, v2);
            else if (!v1IsInFront && back != null)
                result = back.SplitsRay(v1, v2);
        }
        else
        {
            /// this plane splits the ray, but the intersection point may not be within the face boundaries.
            /// 1. calculate the intersection of the plane and the ray : intersection
            /// 2. create two new line segments: v1->intersection and intersection->v2
            /// 3. Recursively check those two segments against the rest of the tree.
            var intersection = new Vector3();

            /// insert code to magically calculate the intersection here.

            var frontSegmentSplits = false;
            var backSegmentSplits = false;


            if (front!=null)
            {
                if (v1IsInFront) frontSegmentSplits=front.SplitsRay(v1,intersection);
                else if (v2IsInFront) frontSegmentSplits=front.SplitsRay(v2,intersection);
            }
            if (back!=null)
            {
                if (!v1IsInFront) backSegmentSplits=back.SplitsRay(v1,intersection);
                else if (!v2IsInFront) backSegmentSplits=back.SplitsRay(v2,intersection);
            }

            result = frontSegmentSplits || backSegmentSplits;
        }

        return result;
    }
} 
  1. メッシュから残りのメッシュを大まかに 2 つに分割する「分割」平面 (面) を選択します。これは、完全に凸状のアイテム (球など) がツリーではなくリストのように見える傾向があるため、複雑なジオメトリで行うのがはるかに簡単です。

  2. BspNodeパーティション プレーンを定義する頂点から新しいインスタンスを作成します。

  3. 残りの面を 2 つのリストに並べ替えます。1 つはパーティション プレーンの前にあり、もう 1 つは後ろにある面を含みます。
  4. リストにノードがなくなるまで、手順 2 に戻ります。

衝突をチェックする場合、2 つのオプションがあります。

  1. シングルポイント: ルート ノードの を呼び出して、ツリーに対してキャラクターまたはオブジェクトが移動している座標を確認します。.IsInFront(moveDestination)メソッドが false を返す場合、ターゲット ポイントはメッシュの「内側」にあり、衝突しています。メソッドが true を返す場合、ターゲット ポイントはメッシュの「外側」にあり、衝突は発生していません。

  2. レイ交差点。これは少しトリッキーになります。.SplitsRay()オブジェクトの現在位置とターゲット位置を指定して、ルート ノードのメソッドを呼び出します。メソッドが を返した場合、true2 つの位置の間を移動すると、メッシュが遷移します。これは優れた (より複雑な) チェックです。目的の動きが 1 つのステップでオブジェクトを完全に通過する場合など、エッジ ケースを検出できるからです。

そのサンプル コードを簡単にまとめてみました。これは不完全で、おそらくコンパイルすらできませんが、正しい方向に進むはずです。

BSP のもう 1 つの優れた点: この.SplitsRay()方法を使用すると、マップ上のあるポイントが別のポイントから見えるかどうかを判断できます。一部のゲームでは、これを使用して、NPC/AI がお互いまたは実際のプレイヤーを見ることができるかどうかを判断します。それを少し変更して、お互いが歩いているのが聞こえるかどうかなどを判断できます。

これは元のアプローチよりもはるかに複雑に見えるかもしれませんが、最終的にははるかに強力で柔軟です。時間をかけて調査する価値があります。

于 2011-04-25T18:08:14.433 に答える