c# - 波前算法

标签 c# windows algorithm xna-4.0

我正在创建一个迷宫程序,其中迷宫是随机生成的,用户必须找到一个随机放置的立方体。现在,我希望能够使用wavefront algorithm让游戏自行解决。 , Dijkstra's algorithm ,或 A* algorithm

这是生成迷宫墙的代码。

    public void GenerateMaze()
    {
        for (int x = 0; x < mazeWidth; x++)
            for (int z = 0; z < mazeHeight; z++)
            {
                MazeCells[x, z].Walls[0] = true;
                MazeCells[x, z].Walls[1] = true;
                MazeCells[x, z].Walls[2] = true;
                MazeCells[x, z].Walls[3] = true;
                MazeCells[x, z].Visited = false;
            }
        MazeCells[0, 0].Visited = true;
        EvaluateCell(new Vector2(0, 0));
    }

    public void resetMaze()
    {
        for (int x = 0; x < mazeWidth; x++)
            for (int z = 0; z < mazeHeight; z++)
            {
                MazeCells[x, z].Visited = false;
            }

        RandomWalls(new Vector2(0, 0));
    }

    private void EvaluateCell(Vector2 cell)
    {
        List<int> neighborCells = new List<int>();
        neighborCells.Add(0);
        neighborCells.Add(1);
        neighborCells.Add(2);
        neighborCells.Add(3);

        while (neighborCells.Count > 0)
        {
            int pick = rand.Next(0, neighborCells.Count);
            int selectedNeighbor = neighborCells[pick];
            neighborCells.RemoveAt(pick);

            Vector2 neighbor = cell;

            switch (selectedNeighbor)
            {
                case 0: neighbor += new Vector2(0, -1);
                    break;
                case 1: neighbor += new Vector2(1, 0);
                    break;
                case 2: neighbor += new Vector2(0, 1);
                    break;
                case 3: neighbor += new Vector2(-1, 0);
                    break;
            }

            if (
                (neighbor.X >= 0) &&
                (neighbor.X < mazeWidth) &&
                (neighbor.Y >= 0) &&
                (neighbor.Y < mazeHeight)
                )
            {
                if (!MazeCells[(int)neighbor.X, (int)neighbor.Y].Visited)
                {
                    MazeCells[(int)neighbor.X, (int)neighbor.Y].Visited = true;
                    MazeCells[(int)cell.X, (int)cell.Y].Walls[selectedNeighbor] = false;
                    MazeCells[(int)neighbor.X, (int)neighbor.Y].Walls[(selectedNeighbor + 2) % 4] = false;
                    EvaluateCell(neighbor);
                }
            }
        }
    }

    //Removes random walls
    private void RandomWalls(Vector2 cell)
    {
        List<int> neighborCells = new List<int>();
        neighborCells.Add(0);
        neighborCells.Add(1);
        neighborCells.Add(2);
        neighborCells.Add(3);

        while (neighborCells.Count > 0)
        {
            int pick = rand.Next(0, neighborCells.Count);
            int selectedNeighbor = neighborCells[pick];
            neighborCells.RemoveAt(pick);

            Vector2 neighbor = cell;

            switch (selectedNeighbor)
            {
                case 0: neighbor += new Vector2(0, -1);
                    break;
                case 1: neighbor += new Vector2(1, 0);
                    break;
                case 2: neighbor += new Vector2(0, 1);
                    break;
                case 3: neighbor += new Vector2(-1, 0);
                    break;
            }

            //Ensures that end piece is not deleted
            if (
                (neighbor.X >= 0) &&
                (neighbor.X < mazeWidth) &&
                (neighbor.Y >= 0) &&
                (neighbor.Y < mazeHeight)
                )
            {

                //if cell was not visited
                if (!MazeCells[(int)neighbor.X, (int)neighbor.Y].Visited)
                {
                    Random random = new Random();

                    MazeCells[(int)neighbor.X, (int)neighbor.Y].Visited = true;

                    //if random number is >= a certain number, removes the walls on both ends
                    if (random.Next(20) >= 15 && removed <= 100)
                    {
                        //MazeCells[(int)neighbor.X, (int)neighbor.Y].Visited = true;
                        MazeCells[(int)cell.X, (int)cell.Y].Walls[selectedNeighbor] = false;
                        MazeCells[(int)neighbor.X, (int)neighbor.Y].Walls[(selectedNeighbor + 2) % 4] = false;
                        removed++;
                    }

                    RandomWalls(neighbor);
                }
            }
        }
    }

对于缺少注释,我深表歉意,但本质上,它将所有单元格放入一个盒子中,然后拆掉墙壁,以便您可以到达迷宫中的任何单元格。然后我只是移除了一些额外的细胞,这样迷宫就不会感觉那么幽闭恐怖了。

这是迷宫的俯 View : enter image description here

迷宫周围有墙,可以将玩家限制在里面,以防很难看到。通常,您更多地将其视为第一人称的观点。

所以,目标:现在,我希望相机找到立方体的位置和相机的位置,然后找到两者之间的最短路线。然后,我希望相机慢慢地沿着路线到达那里,直到它击中立方体。现在,我应该使用哪种算法以及如何使用。

如果有帮助的话,这段代码几乎完全来自XNA 4 3D Game Developement by Example一书。我所做的唯一真正的编辑是 RandomWalls() 方法。

最佳答案

我认为波前算法可能有点太复杂,无法用于解决这个问题,因此在我的回答中,我将研究其他两种图形搜索算法。

您需要采取的第一步是生成迷宫的图形表示。我认为最简单的方法是:

  1. 将 map 中的每个方 block (图 block )表示为图表中的一个节点。
  2. 如果任何两个给定的相邻方 block 之间没有边,则表示这些方 block 的两个节点之间就有一条边。

Graph Representation of the maze

完成后,您需要分配权重。由于在您的情况下,您似乎对一条边或另一条边没有任何偏好,因此将每条边的成本设置为 1 应该没问题。

生成加权图后,您需要对其进行搜索。我认为最流行的两种算法是Dijkstra's Shortest Path AlgorithmA*算法。

据我了解,您没有关于立方体将放置在何处的信息,在我看来,这意味着您不能使用 A* 因为 A* 基于启发式,在本例中,启发式可能是当前节点和目标节点之间的距离,而这是您不知道的。

因此,剩下的唯一选择是最短路径算法。然而,要做到这一点,您需要稍微修改搜索的停止条件,因为您需要检查每个节点代表的方 block 的内容。如果你找到了你要找的东西,你就会停下来。

如果另一方面,由于某种原因您必须使用负权重,那么最短路径将不再起作用。为此,您需要使用相同的方法,但是使用 Label Correcting AlgorithmBellman-Ford Algorithm .

一旦获得从源节点到目标节点的最短路径,您就可以提取一系列向量,将您从一个方格移动到下一个方格。获得这些向量后,您应该能够按照 this 中的说明移动相机。 MSDN 教程。

编辑:你的问题中的这一行:所以,目标:现在,我希望相机找到立方体的位置让我明白你事先不知道立方体在哪里。如果情况并非如此,那么,根据 @Gene 的评论,A* 算法将更合适,因为(假设您知道您的目标在哪里)它将更有效。

曼哈顿距离(见下图)应该很好地充当算法的启发式部分,因为似乎您无法对角线遍历方 block ,因此,计算距离的最常见方法(欧几里得)的效果会较差。

enter image description here

关于c# - 波前算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22872950/

相关文章:

c# - 使用正则表达式替换而不是字符串替换

使用 MSVC 从 Windows Powershell 编译 C 程序

c - 当我们为 50n logn 计算 Big-Oh 时,它是 O(n log n)?我们可以把 O(n^5) 当作 Big-Oh 吗?

c++ - 测量大型方形网格中的簇有哪些好的替代方法?

algorithm - Ford-Fulkerson 算法和最大流最小割定理

c# - Entity Framework 错误为“不允许新事务,因为 session 中还有其他线程正在运行

c# - 如何确定已安装字体的操作系统文件名?

C# CGI 可执行文件——好主意还是坏主意?

windows - Windows 中特定驱动器的磁盘大小

python - 使用linux开发机搭建跨平台桌面应用的推荐方式