程序洞穴生成五(Procedural Cave Generation)

视频原址:https://www.youtube.com/watch?v=eVb9kQXvEZM&index=6&list=PLFt_AvWsXl0eZgMK_DT5_biRkWXftAOf9

本次视频的内容是将分散的房间连接起来,调节RandomFillPercent到合适的值(作者使用53)会发现洞穴生成的房间经过优化之后会有很多小的房间独立起来,那么我们就需要用一种规则将所有的房间连接起来,但是这个视频没有讲完所有的连接过程,只讲了第一步如何去将一部分房间的连接关系获取出来。

好了进入正题,为了方便我们获取房间的信息,所以创建另一个房间的类。

//房间类
    class Room
    {
        public List<Coord> tiles;       //房间所有的方块的Coord类
        public List<Coord> edgTiles;    //房间中所谓作为房间边界的方块的集合
        public List<Room> connectedRooms;   //相连接的房间集合
        public int roomSize;

        //空构造
        public Room()
        {

        }

        //创建房间的时候要传进地图的二维的数据,用于获取边界信息
        public Room(List<Coord> roomTiles, int[,] map)
        {
            tiles = roomTiles;
            roomSize = tiles.Count;
            connectedRooms = new List<Room>();

            edgTiles = new List<Coord>();
            //遍历tiles中所有的方块,如果周围四个方块有方块的地图的信息是墙,说明该方块是边界
            foreach (Coord tile in tiles)
            {
                for (int x = tile.tileX - 1; x <= tile.tileX + 1; x++)
                {
                    for (int y = tile.tileY - 1; y <= tile.tileY + 1; y++)
                    {
                        if (x == tile.tileX || y == tile.tileY)
                        {
                            if (map[x, y] == 1)
                            {
                                edgTiles.Add(tile);
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 连接两个房间的方法,其实就是将A房间添加到B房间的连接房间列表,将B房间添加到房间A的房间列表中
        /// </summary>
        /// <param name="roomA"></param>
        /// <param name="roomB"></param>
        public static void ConnectRooms(Room roomA, Room roomB)
        {
            roomA.connectedRooms.Add(roomB);
            roomB.connectedRooms.Add(roomA);
        }

        //判断传进来的房间是否与自己相连接
        public bool IsConnected(Room otherRoom)
        {
            return connectedRooms.Contains(otherRoom);
        }
    }

房间中主要的三个变量:tiles,房间中所有的方块的信息,edgeTiles,边界的方块的结合和已经跟该房间连接的所有的房间的信息的集合。因为这个视频没有将怎么讲房间的通道创建出来,所以连接两个房间的静态方法非常简单就是将两个房间互相加到对方的连接的房间列表中。

根据上一篇的代码,我们在优化地图的时候将所有小于阈值的房间的信息全部移除并且设置成了墙,因此我们可以拿到所有的大于阈值的房间的并且将这些房间存在一个集合survivingRooms中。然后遍历survivingRooms中所有的房间,将survivingRooms中的每一个房间与survivingRooms中的每个房间的边界方块列表进行处理。处理规则:首先房间的条件判断:如果是两个相同的房间就跳过,如果遍历过程中发现该房间已经有与其他房间相连就跳过。然后就方块的规则,通过获取到两个房间之间的的边界的距离,遍历完一个房间与所有满足条件的房间的所有的边界就能算出并得到两个房间距离最近的房间并且拿到两个距离最近的方块。此时连接两个房间。当两层的循环遍历结束我们就能够拿到一个不错的结果,这个结果能让所有的房间不再是单独的房间,至少会跟一个房间连接。

主要的代码:

 /// <summary>
    /// 连接最近的房间
    /// </summary>
    /// <param name="allRooms"></param>
    void ConnectClosestRooms(List<Room> allRooms)
    {
        int bestDistance = 0;
      
        Coord bestTileA = new Coord();      //房间a与房间b连接的最好也就是最近的两个方块
        Coord bestTileB = new Coord();  
        Room bestRoomA = new Room();        //找到相聚最近的两个房间
        Room bestRoomB = new Room();
        bool possibleConnectionFound = false;   //可能连接的flag,如果为false,说明本次循环不需要为两个房间创建连接
        
        foreach (Room roomA in allRooms)
        {
            possibleConnectionFound = false;

            foreach (Room roomB in allRooms)
            {
                if (roomA == roomB) continue;
                if (roomA.IsConnected(roomB))
                {
                    //遍历发现房间A已经有连接的房间了,设置变量,然后跳过这个房间
                    possibleConnectionFound = false;
                    break;
                }
                //2层for循环遍历房间A和房间B的所有边界方块。
                for (int tileindexA = 0; tileindexA < roomA.edgTiles.Count; tileindexA++)
                {
                    for (int tileIndexB = 0; tileIndexB < roomB.edgTiles.Count; tileIndexB++)
                    {
                        Coord tileA = roomA.edgTiles[tileindexA];
                        Coord tileB = roomB.edgTiles[tileIndexB];
                        //计算两个方块的距离的平方
                        int distanceBetweenRooms = (int)(Mathf.Pow((tileA.tileX - tileB.tileX), 2) + Mathf.Pow((tileA.tileY - tileB.tileY), 2));

                        if (distanceBetweenRooms < bestDistance || !possibleConnectionFound)
                        {
                            bestDistance = distanceBetweenRooms;
                            possibleConnectionFound = true;
                            bestTileA = tileA;
                            bestTileB = tileB;
                            bestRoomA = roomA;
                            bestRoomB = roomB;
                        }
                    }
                }
            }

            if (possibleConnectionFound)
            {
                CreatePassage(bestRoomA, bestRoomB, bestTileA, bestTileB);
            }
        }
    }

    /// <summary>
    /// 创建通道
    /// </summary>
    /// <param name="roomA"></param>
    /// <param name="roomB"></param>
    /// <param name="tileA"></param>
    /// <param name="tileB"></param>
    void CreatePassage(Room roomA, Room roomB, Coord tileA, Coord tileB)
    {
        Room.ConnectRooms(roomA, roomB);

        Debug.DrawLine(CoordToWorldPoint(tileA), CoordToWorldPoint(tileB), Color.green, 100);
    }

    /// <summary>
    /// Coord类型信息获取世界坐标
    /// </summary>
    /// <param name="tile"></param>
    /// <returns></returns>
    Vector3 CoordToWorldPoint(Coord tile)
    {
        return new Vector3(-width / 2 + .5f + tile.tileX, 2, -height / 2 + .5f + tile.tileY);
    }

 

连接的方式暂时用绘制线条的方式来表示:

但是这个效果显示不满足最终的连接的效果的,虽然此时每个房间似乎都至少有跟其他的房间相连接,但是观察能发现,如果将绿色的线做成通道,此时相当于是四个独立的大房间,看到这里我想很多人可以猜到下一个视频作者要怎么处理这个问题了,我也想到了但是不知道视频作者的想法是怎么样的会不会更飘逸。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值