我的迷宫算法哪里出问题了?

问题描述 投票:-1回答:2

我正在尝试使用房间生成迷宫,并且正在使用此guide

This is what I am trying to achieve这就是我要实现的目标。相反,我得到这个:

What I am achieving

这是我到目前为止所做的(删除了不必要的部分)

    using UnityEngine;
using Random = UnityEngine.Random;
using UnityEngine.Tilemaps;

using System.Collections.Generic;
using System.Linq;

public class MazeAndRoomGenerator : MonoBehaviour
{
    TileType[,] levelWall;
    int[,] regions;
    int currentRegion = -1;
    enum TileType { Floor, Wall }


    // CONSTANTS
    readonly static int[] north = { 0, 1 };
    readonly static int[] south = { 0, -1 };
    readonly static int[] east = { 1, 0 };
    readonly static int[] west = { -1, 0 };
    readonly static int[] northEast = { 1, 1 };
    readonly static int[] northWest = { -1, 1 };
    readonly static int[] southEast = { 1, -1 };
    readonly static int[] southWest = { -1, -1 };
    readonly static int[][] northCells = { north, northEast, northWest };
    readonly static int[][] southCells = { south, southEast, southWest };
    readonly static int[][] eastCells = { east, northEast, southEast };
    readonly static int[][] westCells = { west, northWest, southWest };



    public void GenerateMaze()
    {
        // Loop through all cells in the level and grow the maze in all parts that aren't assigned yet
        for (int y = 0; y < mapSize; y += 2)
        {
            for (int x = 0; x < mapSize; x += 2)
            {
                if(levelWall[x,y] == TileType.Wall)
                {
                    GrowMaze(x, y);
                }
            }
        }
    }





    public void Carve(int x, int y)
    {
        levelWall[x,y] = TileType.Floor;
        regions[x, y] = currentRegion;
    }
    public bool CanCarve(int[] pos, int[] dir)
    {
        // Returns false if the cell is already taken or out of map bounds
        int x = pos[0] + dir[0] * 2;
        int y = pos[1] + dir[1] * 2;
        if (!InBounds(x, y)) { return false; }


        int[][] checkCells = null;
        if      (dir == north) { checkCells = northCells; }
        else if (dir == south) { checkCells = southCells; }
        else if (dir == east)  { checkCells = eastCells; }
        else if (dir == west)  { checkCells = westCells; }
        else { Debug.LogError("Incorrect direction inputted"); }

        foreach (int[] checkCell in checkCells)
        {
            int[] cell = { pos[0] + checkCell[0], pos[1] + checkCell[1] };
            if (CanCarve(cell))
            {
                return false;
            }
        }

        // All of the surrounding walls are available so return true
        return true;
    }
    public bool CanCarve(int[] pos)
    {
        // Returns false if the cell is already taken or out of map bounds

        int x = pos[0];
        int y = pos[1];

        // Checking if map is out of bounds
        if (!InBounds(x, y)) 
        { 
            return false; 
        }


        // return True if the cell is a wall (1)
        // false if the cell is a floor (0)
        return (levelWall[x, y] == TileType.Wall);
    }
    public bool InBounds(int x, int y)
    {
        // Checking if map is out of bounds
        if (!(0 < x) || !(x < mapSize) ||
            !(0 < y) || !(y < mapSize))
        {
            return false;
        }
        else return true;
    }
    public void GrowMaze(int startX, int startY)
    {
        /*
         * RULES: 
         *  If any of the neighbour cells to start point (CanCarve == false) are floor then stop.
         *  Take a random available direction and start carving.
         *  For each cell that is carved first check if the cell in front of it (travelling in the same direction)
         *  and the cells to the left and right of the cell is carvable. 
         *  If isn't then remove that direction from available directions and pick new direction from original cell.
         *  Repeat until no available directions left
         */


        int[][] directions = { north, south, east, west };
        int[][] neighbourCells = { north, south, east, west, northEast, northWest, southEast, southWest };

        int[] start = { startX, startY };
        List<int[]> cells = new List<int[]>();
        int[] lastDirection = null;

        // Check if starting point is valid
        foreach (int[] direction in neighbourCells)
        {
            int[] checkCell = { start[0] + direction[0], start[1] + direction[1] };
            if (!CanCarve(checkCell))
            {
                // Throw out start cell and don't start maze from there
                return;
            }
        }

        // Start a new region for the new maze region
        StartRegion();
        Carve(start[0], start[1]);
        cells.Add(start);


        // While there are available cells to travel to run script
        while (cells.Count > 0 && cells.Count < 10000)
        {
            int[] cell = cells[cells.Count - 1];

            List<int[]> unmadeCells = new List<int[]>();

            foreach (int[] direction in directions)
            {
                int[] checkCell = { cell[0] + direction[0], cell[1] + direction[1] };
                if (CanCarve(checkCell, direction))
                {
                    unmadeCells.Add(direction);
                }
            }

            // If there are available cells to travel to run script
            if (unmadeCells.Count > 0)
            {
                // Prefer to continue in the last direction travelling if available
                // Random chance for it to choose a different direction
                int[] direction;

                if (unmadeCells.Contains(lastDirection) 
                    && (Random.value > (windingChance/100)) )
                {
                    direction = lastDirection;
                }
                else
                {
                    direction = unmadeCells[Random.Range(0, unmadeCells.Count)];
                }

                int[] newCell;
                newCell = new int[] { cell[0] + direction[0], cell[1] + direction[1] };
                Carve(newCell[0], newCell[1]);
                // Adds new cell onto stack and script will repeat with this cell until it has no possible directions to travel
                cells.Add(newCell);

                lastDirection = direction;
            }
            else
            {
                cells.RemoveAt(cells.Count - 1);
                lastDirection = null;
            }
        }
    }


}

我有一个想法,cells数组不断增加并因此陷入循环,这就是为什么我在while循环中为调试增加了单元数量的原因。

我对迷宫的规则是:

  • 如果有任何相邻的单元格开始(CanCarve == false),地板然后停下来。
  • 采取随机的可用方向并开始雕刻。
  • 对于每个被雕刻的单元,首先检查其前面的单元(以相同的方向行进)以及该单元左右两侧的单元是否可雕刻。如果不是,则从可用方向中删除该方向,然后从原始单元格中选择新方向。
  • 重复,直到没有可用的指示离开为止>>
  • 非常感谢您的帮助。我一直在为此扯头发:)

我正在尝试用房间生成一个迷宫,并且正在使用本指南。这是我要实现的目标。取而代之的是,我得到了:这是我到目前为止所做的(删除了不必要的部分)...

c# unity3d procedural-generation
2个回答
0
投票

您将xy分别增加2个信号,所以当然


0
投票

之所以生成方格图案,是因为没有在pos功能中检查CanCarve单元。

© www.soinside.com 2019 - 2024. All rights reserved.