2

我正在制作一个墙壁由方形块组成的游戏。墙壁放置在二维网格上,如下所示:

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

现在,当我优化我的碰撞检测时,它有助于将墙壁数量减少到最低限度。在上述情况下,有七个墙块,但如果将这些块组合在一起,则只有两个墙。我很难想出一个最佳解决方案来找到这些组合墙并根据搜索开始的块获得不同的结果(块存储在无序列表中,顺序来自放置它们的顺序编辑)。关于如何解决这个问题的任何想法?它应该是非常基本的东西,但是,你知道,现在是星期五,我不能正常工作。:)

这是我目前的次优代码,它基本上做了两次检查,水平和垂直“连续性”,然后检查哪一个更好。它还存储“已处理”的墙块,因此它们不会被识别两次,但这当然使它在交叉点变得时髦。

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

我会尝试将此视为洪水填充的一种形式。这个想法是你走过网格的任何一个单元格:每次你撞到“墙”时,你都会开始一个泛滥填充,除了泛滥填充只在一个轴上工作(所以不是泛滥到所有四个方向你要么只能上/下或左/右)。

假设你有你的初始网格,并开始从左到右、从上到下迭代单元格:

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

你从左上角的单元格开始,注意它是一堵墙,开始泛滥。由于您只能向右泛洪,因此您进行水平泛洪。您最终覆盖了标有“1”的区域并在列表中记住了该区域:

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

你继续前进,最终撞到了第二排的墙上。你不能向左泛滥(没有墙),你不能向上泛滥(已经被覆盖),你不能向右泛滥(没有墙),但是你可以向下泛滥 - 所以你做一个垂直泛滥:

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

现在你完成了。在这个版本中,“X”永远只是一面墙的一部分。所以如果你有

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

你会有三堵墙:

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

如果您允许淹没被其他墙壁覆盖的“X”单元格,您可能只有两个:

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

'*' 表示被两堵墙覆盖的单元格。

于 2013-06-28T10:08:40.980 回答