[Unity] 二维洞穴地图随机生成

看的别人的示例:
https://blog.csdn.net/l773575310/article/details/72803191
https://github.com/ZeroChiLi/CaveGeneration

在这里插入图片描述

1.地图生成方法

1.新建一个枚举类型的二维数组 map,每个元素代表着每一个格子,枚举内容代表格子的种类,例如空地、墙
2.自定义随机填充算法初始化 map
3.自定义平滑算法处理 map
例如:遍历 map 每个元素,计算其周围 8 个元素为墙的个数,等于 4 个时保持不变,大于一半则自己也变成墙,反之为空地
4.清除小的墙体、空洞
要清除的墙体和空洞是 map 中一些连续的同一枚举类型的元素,用 List<Vector2> 表示,通过广度优先找出
先删掉小墙体,这样有些房间就会变大,找小空洞时,所有房间的大小是最终大小
再删掉小空洞,并且把没删掉的作为房间存起来
最后把房间最大的作为主房间
5.房间连接
遍历所有房间,对其中每一个房间,寻找可能存在的,距离自己最近的,与自己尚未连接的房间
连接时遍历两个房间的边节点,找到两个房间之间距离最近的一对边节点,计算两个点产生的直线的斜率,通过斜率计算直线上的节点,放入列表,遍历这个列表,在以给定的通道宽度为半径,列表元素为圆心的,圆内的所有地图节点,都置为空地
重复遍历若干次,直至连接至主房间的房间数等于所有房间的数量-1

之后的 mesh 相关我不一定用得到,就不想看了hhh

2.对示例代码的修改

Assets/Scripts/Room.cs 中 UpdateEdgeTiles 函数可能会放入重复的边界点

    // 更新房间边缘瓦片集
    public void UpdateEdgeTiles(TileType[,] map)
    {
   
        edgeTiles.Clear();

        // 遍历上下左右四格,判断是否有墙
        foreach (Coord tile in tiles)
            for (int i = 0; i < 4; i++)
            {
   
                int x = tile.tileX + upDownLeftRight[i, 0];
                int y = tile.tileY + upDownLeftRight[i, 1];
                if (map[x, y] == TileType.Wall)
                {
   
                    edgeTiles.Add(tile);
                    continue;
                }
            }
    }

将 Coord 结构体改成 Vector2Int 然后使用 Contain 判断是否已经放过

    // 更新房间边缘瓦片集
    public void UpdateEdgeTiles(TileType[,] map)
    {
   
        edgeTiles.Clear();
        
        // 遍历上下左右四格,判断是否有墙
        foreach (Vector2Int tile in tiles)
            for (int i = 0; i < 4; i++)
            {
   
                int x = tile.x + upDownLeftRight[i, 0];
                int y = tile.y + upDownLeftRight[i, 1];
                if (map[x, y] == TileType.Wall && !edgeTiles.Contains(tile))
                {
   
                    edgeTiles.Add(tile);
                }
            }
    }

源代码连接房间的这一步看不懂捏……

    //连接各个房间。每个房间两两比较,找到最近房间(相对前一个房间)连接之,对第二个房间来说不一定就是最近的。
    //第二个参数为False时,第一步操作:为所有房间都连接到最近房间。
    //第二个参数为True时,第二步操作:就是把所有房间都连接到主房间。
    private void ConnectClosestRooms(List<Room> allRooms, bool forceAccessibilityFromMainRoom = false)
    {
   
        #region 属于第二步操作:roomListA 是还没连接到主房间的房间队列, roomListB 是已经连接到房间B的队列。
        List<Room> roomListA = new List<Room>();
        List<Room> roomListB = new List<Room>();

        if (forceAccessibilityFromMainRoom)                         //是否需要强制连接(直接或间接)到主房间。
        {
   
            foreach (Room room in allRooms)
                if (room.isAccessibleFromMainRoom)
                    roomListB.Add(room);                            //已经连接到主房间的加到ListB。
                else
                    roomListA.Add(room);                            //没有连接到主房间的加到ListA。为空时将结束递归。
        }
        else
        {
   
            roomListA = allRooms;
            roomListB = allRooms;
        }
        #endregion

        int bestDistance = 0;
        Vector2Int bestTileA = new Vector2Int();
        Vector2Int bestTileB = new Vector2Int();
        Room bestRoomA = new Room();
        Room bestRoomB = new Room();
        bool possibleConnectionFound = false;

        foreach (Room roomA in roomListA)                           //遍历没连接到主房间的ListA。
        {
   
            if (!forceAccessibilityFromMainRoom)                    //第一步:如果没有要求连到主房间。
            {
   
                possibleConnectionFound = false;                    //那就不能完成连接任务,需要不止一次连接。
                if (roomA.connectedRooms.Count > 0)                 //有连接房间,跳过,继续找下一个连接房间。
                    continue;
            }
            #region 遍历roomListB,找到距离当前roomA最近的roomB。
            foreach (Room roomB in roomListB)
            {
   
                if (roomA == roomB || roomA.IsConnected(roomB))
                    continue;

                foreach (var tileA in roomA.edgeTiles)
                    foreach (var tileB in roomB.edgeTiles)
                    {
   
                        int distanceBetweenRooms = (tileA - tileB).sqrMagnitude;

                        //如果找到更近的(相对roomA)房间,更新最短路径。
                        if (distanceBetweenRooms < bestDistance || !possibleConnectionFound)
                        {
   
                            bestDistance = distanceBetweenRooms;
                            possibleConnectionFound = true;
                            bestTileA = tileA;
                            bestTileB = tileB;
                            bestRoomA = roomA;
                            bestRoomB = roomB;
                        }
                    }
            }
            #endregion
            //第一步:找到新的两个连接房间,但是没有要求连接主房间。创建通道。
            if (possibleConnectionFound && !forceAccessibilityFromMainRoom)
                CreatePassage(bestRoomA, bestRoomB, bestTileA, bestTileB);
        }

        //第一步到第二步:当连接完所有房间,但是还没有要求全部连接到主房间,那就开始连接到主房间。
        if (!forceAccessibilityFromMainRoom)
            ConnectClosestRooms(allRooms, true);

        //第二步:当成功找到能连接到主房间,通路,继续找一下个能需要连到主房间的房间。
        if (possibleConnectionFound && forceAccessibilityFromMainRoom)
        {
   
            CreatePassage(bestRoomA, bestRoomB, bestTileA, bestTileB);
            ConnectClosestRooms(allRooms, true)
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值