2

壁が四角いブロックでできているゲームを作っています。壁は、次のように 2 次元グリッド上に配置されます。

[X][X][X][X]
[ ][X][ ][ ]
[ ][X][ ][ ]
[ ][X][ ][ ]

現在、衝突検出を最適化しているため、壁の数を最小限に抑えることができます。上記の場合、壁ブロックは7つですが、ブロックを組み合わせると2つの壁しかありません。これらの結合された壁を見つけるための最適な解決策を見つけるのに苦労しており、検索が開始されるブロックに応じてさまざまな結果が得られます (ブロックは順序付けされていないリストに格納され、順序は配置された順序から取得されます)編集者)。これを解決する方法について何か考えはありますか?かなり初歩的なことのはずですが、ほら、今日は金曜日で、正しく機能できません。:)

これが現時点での私の次善のコードです。基本的に、水平方向と垂直方向の「連続性」の両方について2つのチェックを行い、どちらが優れているかをチェックします。また、「既に処理された」壁のブロックを保存するため、2 度認識されることはありませんが、もちろんこれにより交差点でファンキーになります。

public void CreateCollidersForExport()
{
    List<Wall> handledWalls = new List<Wall>();

    foreach (Wall w in walls)
    {
        if (handledWalls.Contains(w)) continue;
        handledWalls.Add(w);

        // Search how many walls there is horizontally
        Vector3 horizontalCenter = new Vector3(w.X, w.Y, w.Z);
        List<Wall> tmpWallsHorizontal = new List<Wall>();
        tmpWallsHorizontal.Add(w);
        foreach (Wall other in walls)
        {
            if (handledWalls.Contains(other) || tmpWallsHorizontal.Contains(other)) continue;
            bool canAdd = false;
            foreach (Wall _w in tmpWallsHorizontal)
            {
                if (other.X == _w.X + Wall.size && other.Y == _w.Y && other.Z == _w.Z)
                {
                    canAdd = true;
                    horizontalCenter.X += Wall.size / 2;
                    break;
                }
                else if (other.X == _w.X - Wall.size && other.Y == _w.Y && other.Z == _w.Z)
                {
                    canAdd = true;
                    horizontalCenter.X -= Wall.size / 2;
                    break;
                }
            }

            if (canAdd)
            {
                tmpWallsHorizontal.Add(other);
            }
        }

        // Search how many walls there is vertically
        Vector3 verticalCenter = new Vector3(w.X, w.Y, w.Z);
        List<Wall> tmpWallsVertical = new List<Wall>();
        tmpWallsVertical.Add(w);
        foreach (Wall other in walls)
        {
            if (handledWalls.Contains(other) || tmpWallsVertical.Contains(other)) continue;
            bool canAdd = false;
            foreach (Wall _w in tmpWallsVertical)
            {
                if (other.X == _w.X && other.Y == _w.Y && other.Z == _w.Z + Wall.size)
                {
                    canAdd = true;
                    verticalCenter.Z += Wall.size / 2;
                    break;
                }
                else if (other.X == _w.X && other.Y == _w.Y && other.Z == _w.Z - Wall.size)
                {
                    canAdd = true;
                    verticalCenter.Z -= Wall.size / 2;
                    break;
                }
            }

            if (canAdd)
            {
                tmpWallsVertical.Add(other);
            }
        }

        if (tmpWallsHorizontal.Count > tmpWallsVertical.Count)
        {
            // tmpWallsHorizontal has the longest "wall" now
        }
        else if (tmpWallsVertical.Count > tmpWallsHorizontal.Count)
        {
            // tmpWallsVertical has the longest "wall" now
        }
        else
        {
            // Both ways are the same length
        }
    }
}
4

1 に答える 1

1

これをフラッド フィルの一種として扱いたいと思います。アイデアは、グリッドのセルの上を歩くことです。「壁」にぶつかるたびに塗りつぶしを開始しますが、塗りつぶしは単一の軸でのみ機能します (したがって、4 つの方向すべてに塗りつぶす代わりに、上下または左右にのみ移動します)。

初期グリッドがあり、セルを左から右、上から下に反復し始めると仮定します。

[X][X][X][X]
[ ][X][ ][ ]
[ ][X][ ][ ]
[ ][X][ ][ ]

左上のセルから始めて、それが壁であることに気付き、フラッディングを開始します。右にしか浸水できないので、横に浸水します。「1」でマークされた領域をカバーすることになり、その領域をリストに記憶します。

[1][1][1][1]                  0/0 -> 3/0
[ ][X][ ][ ]
[ ][X][ ][ ]
[ ][X][ ][ ]

あなたは先に進み、最終的に2列目の壁にぶつかります。左に浸水することはできません (壁なし)、浸水することはできません (すでに覆われています)、右に浸水することはできません (壁なし)。

[1][1][1][1]                  1: 0/0 -> 3/0
[ ][2][ ][ ]                  2: 1/1 -> 1/3
[ ][2][ ][ ]
[ ][2][ ][ ]

これで完了です。このバージョンでは、「X」は常に 1 つの壁の一部にすぎません。もしあなたが持っていたら

[ ][X][ ][ ]
[X][X][X][X]
[ ][X][ ][ ]
[ ][X][ ][ ]

次の 3 つの壁があります。

[ ][1][ ][ ]                  1: 1/0 -> 1/3
[2][1][3][3]                  2: 0/1 -> 0/1
[ ][1][ ][ ]                  3: 2/1 -> 3/1
[ ][1][ ][ ]

他の壁で覆われた 'X' セルのフラッディングを許可する場合は、次の 2 つだけにすることができます。

[ ][1][ ][ ]                  1: 1/0 -> 1/3
[2][*][2][2]                  2: 0/1 -> 3/1
[ ][1][ ][ ]
[ ][1][ ][ ]

「*」は、2 つの壁で覆われたセルを示します。

于 2013-06-28T10:08:40.980 に答える