//从这个点开始获取区域,广度优先算法。
    private List <CaveCoord> GetRegionTiles(int startX, int startY, TileType tileType, ref bool[,] mapFlags)
    {
        List <CaveCoord> tiles  = new List <CaveCoord>();
        Queue <CaveCoord> queue = new Queue <CaveCoord>();

        queue.Enqueue(new CaveCoord(startX, startY));
        mapFlags[startX, startY] = true;

        while (queue.Count > 0)
        {
            CaveCoord tile = queue.Dequeue();                       //弹出队列第一个,添加到要返回的列表里面。
            tiles.Add(tile);

            // 遍历上下左右四格
            for (int i = 0; i < 4; i++)
            {
                int x = tile.tileX + GameMathf.UpDownLeftRight[i, 0];
                int y = tile.tileY + GameMathf.UpDownLeftRight[i, 1];
                if (IsInMapRange(x, y) && mapFlags[x, y] == false && map[x, y] == tileType)
                {
                    mapFlags[x, y] = true;
                    queue.Enqueue(new CaveCoord(x, y));
                }
            }
        }

        return(tiles);
    }
    //获取两点直接线段经过的点。
    private List <CaveCoord> GetLine(CaveCoord from, CaveCoord to)
    {
        List <CaveCoord> line = new List <CaveCoord>();

        int x = from.tileX;
        int y = from.tileY;

        int dx = to.tileX - from.tileX;
        int dy = to.tileY - from.tileY;

        bool inverted    = false;
        int step         = Math.Sign(dx);
        int gradientStep = Math.Sign(dy);

        int longest  = Mathf.Abs(dx);
        int shortest = Mathf.Abs(dy);

        if (longest < shortest)
        {
            inverted = true;
            longest  = Mathf.Abs(dy);
            shortest = Mathf.Abs(dx);

            step         = Math.Sign(dy);
            gradientStep = Math.Sign(dx);
        }

        int gradientAccumulation = longest / 2;         //梯度积累,最长边的一半。

        for (int i = 0; i < longest; i++)
        {
            line.Add(new CaveCoord(x, y));

            if (inverted)
            {
                y += step;
            }
            else
            {
                x += step;
            }

            gradientAccumulation += shortest;           //梯度每次增长为短边的长度。
            if (gradientAccumulation >= longest)
            {
                if (inverted)
                {
                    x += gradientStep;
                }
                else
                {
                    y += gradientStep;
                }
                gradientAccumulation -= longest;
            }
        }

        return(line);
    }
    //创建两个房间的通道。
    private void CreatePassage(CaveRoom roomA, CaveRoom roomB, CaveCoord tileA, CaveCoord tileB)
    {
        CaveRoom.ConnectRooms(roomA, roomB);
        //Debug.DrawLine(CoordToWorldPoint(tileA), CoordToWorldPoint(tileB), Color.green, 100);

        List <CaveCoord> line = GetLine(tileA, tileB);

        foreach (CaveCoord coord in line)
        {
            DrawCircle(coord, passageWidth);
        }
    }
Exemple #4
0
    /// <summary>
    /// 更新区域平均点
    /// </summary>
    private void UpdateAverageCoord()
    {
        if (tiles.Count == 0)
        {
            Debug.LogWarning("CaveRegion tiles Count Is Zero.");
            averageCoord = new CaveCoord(0, 0);
            return;
        }
        float x = 0, y = 0;

        for (int i = 0; i < tiles.Count; i++)
        {
            x += tiles[i].tileX;
            y += tiles[i].tileY;
        }
        averageCoord = new CaveCoord(Mathf.RoundToInt(x / tiles.Count), Mathf.RoundToInt(y / tiles.Count));
    }
 //以点c为原点,r为半径,画圈(拆墙)。
 private void DrawCircle(CaveCoord c, int r)
 {
     for (int x = -r; x <= r; x++)
     {
         for (int y = -r; y <= r; y++)
         {
             if (x * x + y * y <= r * r)
             {
                 int drawX = c.tileX + x;
                 int drawY = c.tileY + y;
                 if (IsInMapRange(drawX, drawY))
                 {
                     map[drawX, drawY] = TileType.Empty;
                 }
             }
         }
     }
 }
Exemple #6
0
 /// <summary>
 /// 两坐标之间平方之和
 /// </summary>
 public float SqrMagnitude(CaveCoord coordB)
 {
     return((tileX - coordB.tileX) * (tileX - coordB.tileX) + (tileY - coordB.tileY) * (tileY - coordB.tileY));
 }
 /// <summary>
 /// 获取坐标对应实际位置
 /// </summary>
 public Vector3 GetPosition(CaveCoord tile)
 {
     return(offset + new Vector3(tile.tileX, 0, tile.tileY));
 }
 //把xy坐标转换成实际坐标。
 private Vector3 CoordToWorldPoint(CaveCoord tile)
 {
     return(new Vector3(-width / 2 + .5f + tile.tileX, 2, -height / 2 + .5f + tile.tileY));
 }
    //连接各个房间。每个房间两两比较,找到最近房间(相对前一个房间)连接之,对第二个房间来说不一定就是最近的。
    //第二个参数为False时,第一步操作:为所有房间都连接到最近房间。
    //第二个参数为True时,第二步操作:就是把所有房间都连接到主房间。
    private void ConnectClosestRooms(List <CaveRoom> allRooms, bool forceAccessibilityFromMainRoom = false)
    {
        #region 属于第二步操作:roomListA 是还没连接到主房间的房间队列, roomListB 是已经连接到房间B的队列。
        List <CaveRoom> roomListA = new List <CaveRoom>();
        List <CaveRoom> roomListB = new List <CaveRoom>();

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

        int bestDistance             = 0;
        CaveCoord bestTileA          = new CaveCoord();
        CaveCoord bestTileB          = new CaveCoord();
        CaveRoom bestRoomA           = new CaveRoom();
        CaveRoom bestRoomB           = new CaveRoom();
        bool possibleConnectionFound = false;

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

                for (int tileIndexA = 0; tileIndexA < roomA.edgeTiles.Count; tileIndexA++)
                {
                    for (int tileIndexB = 0; tileIndexB < roomB.edgeTiles.Count; tileIndexB++)
                    {
                        CaveCoord tileA          = roomA.edgeTiles[tileIndexA];
                        CaveCoord tileB          = roomB.edgeTiles[tileIndexB];
                        int distanceBetweenRooms = (int)tileA.SqrMagnitude(tileB);

                        //如果找到更近的(相对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);
        }
    }