Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / DungeonGenerator.cs

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

/// <summary>
/// 地牢生成器
/// </summary>
public class DungeonGenerator
{
    /// <summary>
    /// 所有生成的房间, 调用过 Generate() 函数才能获取到值
    /// </summary>
    public List<RoomInfo> RoomInfos { get; } = new List<RoomInfo>();

    /// <summary>
    /// 起始房间
    /// </summary>
    public RoomInfo StartRoomInfo { get; private set; }

    /// <summary>
    /// 战斗房间
    /// </summary>
    public List<RoomInfo> BattleRoomInfos { get; } = new List<RoomInfo>();
    
    /// <summary>
    /// 结束房间
    /// </summary>
    public List<RoomInfo> EndRoomInfos { get; } = new List<RoomInfo>();

    /// <summary>
    /// boss房间
    /// </summary>
    public List<RoomInfo> BossRoomInfos { get; } = new List<RoomInfo>();
    
    /// <summary>
    /// 奖励房间
    /// </summary>
    public List<RoomInfo> RewardRoomInfos { get; } = new List<RoomInfo>();

    /// <summary>
    /// 商店房间
    /// </summary>
    public List<RoomInfo> ShopRoomInfos { get; } = new List<RoomInfo>();
    
    /// <summary>
    /// 地牢配置数据
    /// </summary>
    public DungeonConfig Config { get; }
    /// <summary>
    /// 所属地牢组
    /// </summary>
    public DungeonRoomGroup RoomGroup { get; }

    /// <summary>
    /// 随机数对象
    /// </summary>
    public SeedRandom Random;

    //用于标记地图上的坐标是否被占用
    private InfiniteGrid<bool> _roomGrid { get; } = new InfiniteGrid<bool>();
    
    //房间id
    private int _id;
    
    //下一个房间类型
    private DungeonRoomType _nextRoomType = DungeonRoomType.None;
    
    //区域限制
    private int _rangeX = 120;
    private int _rangeY = 120;
    
    //找房间失败次数, 过大则会关闭区域限制
    private int _maxFailCount = 10;
    private int _failCount = 0;

    //最大尝试次数
     private int _maxTryCount = 10;
    private int _currMaxLayer = 0;

    //地牢房间规则处理类
    private DungeonRule _rule;
    
    //上一个房间
    private RoomInfo prevRoomInfo = null;
    private readonly List<RoomInfo> _tempList = new List<RoomInfo>();
    
    private List<DungeonRoomSplit> _battleRoomList;
    
    public DungeonGenerator(DungeonConfig config, SeedRandom seedRandom)
    {
        Config = config;
        Random = seedRandom;
        RoomGroup = GameApplication.Instance.RoomConfig[config.GroupName];
        _rangeX = config.RangeX;
        _rangeY = config.RangeY;

        //验证该组是否满足生成地牢的条件
        var result = DungeonManager.CheckDungeon(config.GroupName);
        if (result.HasError)
        {
            throw new Exception("当前组'" + config.GroupName + "'" + result.ErrorMessage + ", 不能生成地牢!");
        }
        
        Debug.Log("创建地牢生成器, 随机种子: " + Random.Seed);
        RoomGroup.InitWeight(Random);

        _battleRoomList = RoomGroup.BattleList.ToList();
    }

    /// <summary>
    /// 遍历所有房间
    /// </summary>
    public void EachRoom(Action<RoomInfo> cb)
    {
        EachRoom(StartRoomInfo, cb);
    }

    private void EachRoom(RoomInfo roomInfo, Action<RoomInfo> cb)
    {
        if (roomInfo == null)
        {
            return;
        }

        cb(roomInfo);
        foreach (var next in roomInfo.Next)
        {
            EachRoom(next, cb);
        }
    }
    
    /// <summary>
    /// 用于协程中的遍历所有房间
    /// </summary>
    public IEnumerator EachRoomCoroutine(Action<RoomInfo> cb)
    {
        return EachRoomCoroutine(StartRoomInfo, cb);
    }
    
    private IEnumerator EachRoomCoroutine(RoomInfo roomInfo, Action<RoomInfo> cb)
    {
        if (roomInfo == null)
        {
            yield break;
        }

        cb(roomInfo);
        foreach (var next in roomInfo.Next)
        {
            yield return EachRoomCoroutine(next, cb);
        }
    }

    /// <summary>
    /// 生成房间
    /// </summary>
    public bool Generate(DungeonRule rule)
    {
        if (StartRoomInfo != null) return false;
        _rule = rule;
        
        //最大尝试次数
        var maxTryCount = 1000;

        //当前尝试次数
        var currTryCount = 0;

        if (Config.HasDesignatedRoom) //指定房间列表
        {
            for (var i = 0; i < Config.DesignatedRoom.Count; i++)
            {
                var roomSplit = Config.DesignatedRoom[i];
                var nextRoomType = roomSplit.RoomInfo.RoomType;
                var errorCode = GenerateRoom(prevRoomInfo, roomSplit.RoomInfo.RoomType, out var nextRoom);
                if (errorCode == GenerateRoomErrorCode.NoError) //生成成功
                {
                    _failCount = 0;
                    RoomInfos.Add(nextRoom);
                    if (nextRoomType == DungeonRoomType.Inlet)
                    {
                        StartRoomInfo = nextRoom;
                    }
                    else if (nextRoomType == DungeonRoomType.Boss) //boss房间
                    {
                        BossRoomInfos.Add(nextRoom);
                    }
                    else if (nextRoomType == DungeonRoomType.Outlet)
                    {
                        EndRoomInfos.Add(nextRoom);
                    }
                    else if (nextRoomType == DungeonRoomType.Battle)
                    {
                        BattleRoomInfos.Add(nextRoom);
                    }
                    else if (nextRoomType == DungeonRoomType.Reward)
                    {
                        RewardRoomInfos.Add(nextRoom);
                    }
                    else if (nextRoomType == DungeonRoomType.Shop)
                    {
                        ShopRoomInfos.Add(nextRoom);
                    }

                    prevRoomInfo = nextRoom;
                }
                else //生成失败
                {
                    //Debug.Log("生成第" + (_count + 1) + "个房间失败! 失败原因: " + errorCode);
                    if (errorCode == GenerateRoomErrorCode.OutArea)
                    {
                        _failCount++;
                        //Debug.Log("超出区域失败次数: " + _failCount);
                        if (_failCount >= _maxFailCount)
                        {
                            //_enableLimitRange = false;
                            _failCount = 0;
                            _rangeX += 50;
                            _rangeY += 50;
                            //Debug.Log("生成房间失败次数过多, 增大区域");
                        }
                    }

                    currTryCount++;
                    if (currTryCount >= maxTryCount)
                    {
                        Debug.Log("生成失败, 房间总数: " + RoomInfos.Count);
                        return false;
                    }

                    i--;
                }
            }
        }
        else //正常随机生成
        {
            //如果房间数量不够, 就一直生成
            while (!_rule.CanOverGenerator())
            {
                if (_nextRoomType == DungeonRoomType.None)
                {
                    _nextRoomType = _rule.GetNextRoomType(prevRoomInfo);
                }

                var nextRoomType = _nextRoomType;

                //上一个房间
                var tempPrevRoomInfo = _rule.GetConnectPrevRoom(prevRoomInfo, nextRoomType);
                //生成下一个房间
                var errorCode = GenerateRoom(tempPrevRoomInfo, nextRoomType, out var nextRoom);
                if (errorCode == GenerateRoomErrorCode.NoError) //生成成功
                {
                    _failCount = 0;
                    RoomInfos.Add(nextRoom);
                    if (nextRoomType == DungeonRoomType.Inlet)
                    {
                        StartRoomInfo = nextRoom;
                    }
                    else if (nextRoomType == DungeonRoomType.Boss) //boss房间
                    {
                        BossRoomInfos.Add(nextRoom);
                    }
                    else if (nextRoomType == DungeonRoomType.Outlet)
                    {
                        EndRoomInfos.Add(nextRoom);
                    }
                    else if (nextRoomType == DungeonRoomType.Battle)
                    {
                        BattleRoomInfos.Add(nextRoom);
                    }
                    else if (nextRoomType == DungeonRoomType.Reward)
                    {
                        RewardRoomInfos.Add(nextRoom);
                    }
                    else if (nextRoomType == DungeonRoomType.Shop)
                    {
                        ShopRoomInfos.Add(nextRoom);
                    }

                    prevRoomInfo = nextRoom;
                    _rule.GenerateRoomSuccess(tempPrevRoomInfo, nextRoom);
                    _nextRoomType = _rule.GetNextRoomType(nextRoom);
                }
                else //生成失败
                {
                    _rule.GenerateRoomFail(tempPrevRoomInfo, nextRoomType);

                    //Debug.Log("生成第" + (RoomInfos.Count + 1) + "个房间失败! 失败原因: " + errorCode);
                    if (errorCode == GenerateRoomErrorCode.OutArea)
                    {
                        _failCount++;
                        //Debug.Log("超出区域失败次数: " + _failCount);
                        if (_failCount >= _maxFailCount)
                        {
                            //_enableLimitRange = false;
                            _failCount = 0;
                            _rangeX += 50;
                            _rangeY += 50;
                            //Debug.Log("生成房间失败次数过多, 增大区域");
                        }
                    }

                    currTryCount++;
                    if (currTryCount >= maxTryCount)
                    {
                        Debug.Log("生成失败, 房间总数: " + RoomInfos.Count);
                        return false;
                    }
                }
            }
        }

        _roomGrid.Clear();
        Debug.Log("房间总数: " + RoomInfos.Count);
        Debug.Log("尝试次数: " + currTryCount);
        return true;
    }

    //生成房间
    private GenerateRoomErrorCode GenerateRoom(RoomInfo prevRoom, DungeonRoomType roomType, out RoomInfo resultRoomInfo)
    {
        // if (_count >= _config.RoomCount)
        // {
        //     resultRoom = null;
        //     return GenerateRoomErrorCode.RoomFull;
        // }

        DungeonRoomSplit roomSplit;
        if (Config.HasDesignatedRoom && Config.DesignatedRoom[RoomInfos.Count] != null) //执行指定了房间
        {
            roomSplit = Config.DesignatedRoom[RoomInfos.Count];
        }
        else //没有指定房间
        {
            //随机选择一个房间
            var list = RoomGroup.GetRoomList(roomType);
            if (list.Count == 0) //如果没有指定类型的房间, 或者房间数量不够, 就生成战斗房间
            {
                roomSplit = RoomGroup.GetRandomRoom(DungeonRoomType.Battle);
            }
            else
            {
                //原代码
                //roomSplit = RoomGroup.GetRandomRoom(roomType);
                
                //临时处理, 不生成相同的战斗房间
                if (roomType == DungeonRoomType.Battle && _battleRoomList.Count > 0)
                {
                    roomSplit = Random.RandomChooseAndRemove(_battleRoomList);
                }
                else
                {
                    roomSplit = RoomGroup.GetRandomRoom(roomType);
                }
            }
        }
        
        var room = new RoomInfo(_id, roomType, roomSplit);

        //房间大小
        room.Size = new Vector2I((int)roomSplit.RoomInfo.Size.X, (int)roomSplit.RoomInfo.Size.Y);

        if (prevRoom != null) //表示这不是第一个房间, 就得判断当前位置下的房间是否被遮挡
        {
            room.Layer = prevRoom.Layer + 1;
            if (_currMaxLayer < room.Layer)
            {
                _currMaxLayer = room.Layer;
            }
            //生成的位置可能会和上一个房间对不上, 需要多次尝试
            var tryCount = 0; //当前尝试次数
            var maxTryCount = _maxTryCount; //最大尝试次数
            if (roomType == DungeonRoomType.Outlet)
            {
                maxTryCount *= 3;
            }
            else if (roomType == DungeonRoomType.Boss)
            {
                maxTryCount *= 2;
            }
            for (; tryCount < maxTryCount; tryCount++)
            {
                //下一个房间方向
                var direction = _rule.GetNextRoomDoorDirection(prevRoom, roomType);
                //房间间隔
                var space = _rule.GetNextRoomInterval(prevRoom, roomType, direction);
                //中心偏移
                var offset = _rule.GetNextRoomOffset(prevRoom, roomType, direction);

                //计算房间位置
                if (direction == RoomDirection.Up) //上
                {
                    room.Position = new Vector2I(prevRoom.Position.X + offset,
                        prevRoom.Position.Y - room.Size.Y - space - 1);
                }
                else if (direction == RoomDirection.Right) //右
                {
                    room.Position = new Vector2I(prevRoom.Position.X + prevRoom.Size.X + space,
                        prevRoom.Position.Y + offset);
                }
                else if (direction == RoomDirection.Down) //下
                {
                    room.Position = new Vector2I(prevRoom.Position.X + offset,
                        prevRoom.Position.Y + prevRoom.Size.Y + space);
                }
                else if (direction == RoomDirection.Left) //左
                {
                    room.Position = new Vector2I(prevRoom.Position.X - room.Size.X - space,
                        prevRoom.Position.Y + offset);
                }

                //是否在限制区域内
                if (Config.EnableLimitRange)
                {
                    if (room.GetHorizontalStart() < -_rangeX || room.GetHorizontalEnd() > _rangeX ||
                        room.GetVerticalStart() < -_rangeY || room.GetVerticalEnd() > _rangeY)
                    {
                        //超出区域, 直接跳出尝试的循环, 返回 null
                        resultRoomInfo = null;
                        return GenerateRoomErrorCode.OutArea;
                    }
                }

                //是否碰到其他房间或者过道
                if (_roomGrid.RectCollision(room.Position - new Vector2I(2, 2), room.Size + new Vector2I(4, 5)))
                {
                    //碰到其他墙壁, 再一次尝试
                    continue;
                    //return GenerateRoomErrorCode.HasCollision;
                }
                
                _roomGrid.SetRect(room.Position, room.Size, true);

                //找门, 与上一个房间是否能连通
                if (!ConnectDoor(prevRoom, room))
                {
                    _roomGrid.RemoveRect(room.Position, room.Size);
                    //Debug.Log("链接通道失败");
                    //房间过道没有连接上, 再一次尝试
                    continue;
                    //return GenerateRoomErrorCode.NoProperDoor;
                }
                break;
            }

            //尝试次数用光了, 还没有找到合适的位置
            if (tryCount >= maxTryCount)
            {
                resultRoomInfo = null;
                return GenerateRoomErrorCode.NoSuitableLocation;
            }
        }
        else //第一个房间
        {
            room.Layer = 0;
            _roomGrid.SetRect(room.Position, room.Size, true);
        }
        
        _id++;
        room.Prev = prevRoom;
        if (prevRoom != null)
        {
            prevRoom.Next.Add(room);
        }
        resultRoomInfo = room;
        return GenerateRoomErrorCode.NoError;
    }

    /// <summary>
    /// 设置上一个房间
    /// </summary>
    public void SetPrevRoom(RoomInfo roomInfo)
    {
        prevRoomInfo = roomInfo;
    }

    /// <summary>
    /// 回滚一个房间
    /// </summary>
    public bool RollbackRoom(RoomInfo roomInfo)
    {
        if (roomInfo.Next.Count > 0)
        {
            Debug.LogError("当前房间还有连接的子房间, 不能回滚!");
            return false;
        }

        if (!roomInfo.CanRollback)
        {
            Debug.LogError("当前房间不能回滚!");
            return false;
        }
        var prevRoom = roomInfo.Prev;
        
        //退掉占用的房间区域和过道占用区域
        _roomGrid.RemoveRect(roomInfo.Position, roomInfo.Size);
        foreach (var rect2 in roomInfo.AisleArea)
        {
            _roomGrid.RemoveRect(rect2.Position, rect2.Size);
        }
        
        //roomInfo.Doors[0].
        if (prevRoom != null)
        {
            roomInfo.Prev.Next.Remove(roomInfo);
        }

        roomInfo.Prev = null;
        foreach (var roomInfoDoor in roomInfo.Doors)
        {
            var connectDoor = roomInfoDoor.ConnectDoor;
            connectDoor.RoomInfo.Doors.Remove(connectDoor);
        }

        RoomInfos.Remove(roomInfo);
        switch (roomInfo.RoomType)
        {
            case DungeonRoomType.Battle:
                BattleRoomInfos.Remove(roomInfo);
                break;
            case DungeonRoomType.Inlet:
                StartRoomInfo = null;
                break;
            case DungeonRoomType.Outlet:
                EndRoomInfos.Remove(roomInfo);
                break;
            case DungeonRoomType.Boss:
                BossRoomInfos.Remove(roomInfo);
                break;
            case DungeonRoomType.Reward:
                RewardRoomInfos.Remove(roomInfo);
                break;
            case DungeonRoomType.Shop:
                ShopRoomInfos.Remove(roomInfo);
                break;
            case DungeonRoomType.Event:
                break;
        }
        
        roomInfo.Destroy();
        _id--;
        _nextRoomType = DungeonRoomType.None;
        SetPrevRoom(prevRoom);
        return true;
    }

    /// <summary>
    /// 寻找层级最高的房间
    /// </summary>
    /// <param name="roomType">指定房间类型, 如果传 None 则表示选择所有类型房间</param>
    /// <param name="exclude">排除的房间</param>
    public RoomInfo FindMaxLayerRoom(DungeonRoomType roomType, List<RoomInfo> exclude = null)
    {
        RoomInfo temp = null;
        foreach (var roomInfo in RoomInfos)
        {
            if (roomInfo.CanRollback)
            {
                continue;
            }
            if ((temp == null || roomInfo.Layer > temp.Layer) && (roomType == DungeonRoomType.None || (roomInfo.RoomType & roomType) != DungeonRoomType.None) && (exclude == null || !exclude.Contains(roomInfo)))
            {
                temp = roomInfo;
            }
        }

        return temp;
    }

    /// <summary>
    /// 随机抽取层级小于 layer 的房间
    /// </summary>
    /// <param name="roomType">指定房间类型, 如果传 None 则表示选择所有类型房间</param>
    /// <param name="layer"></param>
    /// <param name="exclude">排除的房间</param>
    public RoomInfo RandomRoomLessThanLayer(DungeonRoomType roomType, int layer, List<RoomInfo> exclude = null)
    {
        _tempList.Clear();
        foreach (var roomInfo in RoomInfos)
        {
            if (roomInfo.CanRollback)
            {
                continue;
            }
            if (roomInfo.Layer < layer && (roomType == DungeonRoomType.None || (roomInfo.RoomType & roomType) != DungeonRoomType.None) && (exclude == null || !exclude.Contains(roomInfo)))
            {
                _tempList.Add(roomInfo);
            }
        }

        return Random.RandomChoose(_tempList);
    }
    
    /// <summary>
    /// 随机抽取层级大于 layer 的房间
    /// </summary>
    /// <param name="roomType">指定房间类型, 如果传 None 则表示选择所有类型房间</param>
    /// <param name="layer"></param>
    /// <param name="exclude">排除的房间</param>
    public RoomInfo RandomRoomGreaterThanLayer(DungeonRoomType roomType, int layer, List<RoomInfo> exclude = null)
    {
        _tempList.Clear();
        foreach (var roomInfo in RoomInfos)
        {
            if (roomInfo.CanRollback)
            {
                continue;
            }
            if (roomInfo.Layer > layer && (roomType == DungeonRoomType.None || (roomInfo.RoomType & roomType) != DungeonRoomType.None) && (exclude == null || !exclude.Contains(roomInfo)))
            {
                _tempList.Add(roomInfo);
            }
        }

        return Random.RandomChoose(_tempList);
    }
    
    /// <summary>
    /// 随机抽取房间
    /// </summary>
    /// <param name="roomType">指定房间类型, 如果传 None 则表示选择所有类型房间</param>
    public RoomInfo GetRandomRoom(DungeonRoomType roomType)
    {
        _tempList.Clear();
        foreach (var roomInfo in RoomInfos)
        {
            if (roomInfo.CanRollback)
            {
                continue;
            }

            if (roomType == DungeonRoomType.None || (roomInfo.RoomType & roomType) != DungeonRoomType.None)
            {
                _tempList.Add(roomInfo);
            }
        }

        return Random.RandomChoose(_tempList);
    }

    /// <summary>
    /// 提交所有可以回滚的房间
    /// </summary>
    public void SubmitCanRollbackRoom()
    {
        foreach (var roomInfo in RoomInfos)
        {
            roomInfo.CanRollback = false;
        }
    }
    
    /// <summary>
    /// 找两个房间的门
    /// </summary>
    private bool ConnectDoor(RoomInfo roomInfo, RoomInfo nextRoomInfo)
    {
        //门描述
        var roomDoor = new RoomDoorInfo();
        var nextRoomDoor = new RoomDoorInfo();
        roomDoor.RoomInfo = roomInfo;
        roomDoor.IsForward = true;
        nextRoomDoor.RoomInfo = nextRoomInfo;
        roomDoor.ConnectRoom = nextRoomInfo;
        roomDoor.ConnectDoor = nextRoomDoor;
        nextRoomDoor.ConnectRoom = roomInfo;
        nextRoomDoor.ConnectDoor = roomDoor;

        //先寻找直通门
        if (Random.RandomBoolean())
        {
            //直行通道, 优先纵轴
            if (TryConnectVerticalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor)
                || TryConnectHorizontalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor))
            {
                return true;
            }
        }
        else
        {
            //直行通道, 优先横轴
            if (TryConnectHorizontalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor)
                || TryConnectVerticalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor))
            {
                return true;
            }
        }

        if (Config.AllowedCornerAisles)
        {
            //包含1个拐角的通道
            return TryConnectCrossDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor);
            //包含2个拐角的通道 (后面再开发)
        }

        return false;
    }

    /// <summary>
    /// 尝试寻找纵轴方向上两个房间的连通的门, 只查找直线通道, 返回是否找到
    /// </summary>
    private bool TryConnectVerticalDoor(RoomInfo roomInfo, RoomDoorInfo roomDoor, RoomInfo nextRoomInfo, RoomDoorInfo nextRoomDoor)
    {
        var overlapX = Mathf.Min(roomInfo.GetHorizontalEnd(), nextRoomInfo.GetHorizontalEnd()) -
                       Mathf.Max(roomInfo.GetHorizontalStart(), nextRoomInfo.GetHorizontalStart());
        //这种情况下x轴有重叠
        if (overlapX >= 6)
        {
            //填充通通道地板格子
            var floorCell = new HashSet<Vector2I>();
            
            //找到重叠区域
            var rangeList = FindPassage(roomInfo, nextRoomInfo, 
                roomInfo.GetVerticalStart() < nextRoomInfo.GetVerticalStart() ? DoorDirection.S : DoorDirection.N);
            
            while (rangeList.Count > 0)
            {
                //找到重叠区域
                var range = Random.RandomChooseAndRemove(rangeList);
                var x = Random.RandomRangeInt(range.X, range.Y) + 2;
                
                if (roomInfo.GetVerticalStart() < nextRoomInfo.GetVerticalStart()) //room在上, nextRoom在下
                {
                    roomDoor.Direction = DoorDirection.S;
                    nextRoomDoor.Direction = DoorDirection.N;
                    roomDoor.OriginPosition = new Vector2I(x, roomInfo.GetVerticalDoorEnd());
                    nextRoomDoor.OriginPosition = new Vector2I(x, nextRoomInfo.GetVerticalDoorStart());

                    var sv = roomInfo.GetVerticalDoorEnd() - 1;
                    var ev = nextRoomInfo.GetVerticalDoorStart() + 1;
                    for (var i = sv; i < ev; i++)
                    {
                        floorCell.Add(new Vector2I(x + 1, i));
                        floorCell.Add(new Vector2I(x + 2, i));
                    }
                }
                else //room在下, nextRoom在上
                {
                    roomDoor.Direction = DoorDirection.N;
                    nextRoomDoor.Direction = DoorDirection.S;
                    roomDoor.OriginPosition = new Vector2I(x, roomInfo.GetVerticalDoorStart());
                    nextRoomDoor.OriginPosition = new Vector2I(x, nextRoomInfo.GetVerticalDoorEnd());

                    var sv = nextRoomInfo.GetVerticalDoorEnd() - 1;
                    var ev = roomInfo.GetVerticalDoorStart() + 1;
                    for (var i = sv; i < ev; i++)
                    {
                        floorCell.Add(new Vector2I(x + 1, i));
                        floorCell.Add(new Vector2I(x + 2, i));
                    }
                }

                //判断门之间的通道是否有物体碰到
                if (!AddCorridorToGridRange(roomDoor, nextRoomDoor))
                {
                    //此门不能连通
                    floorCell.Clear();
                    continue;
                }

                //没有撞到物体
                roomInfo.Doors.Add(roomDoor);
                nextRoomInfo.Doors.Add(nextRoomDoor);

                roomDoor.AisleFloorCell = floorCell;
                nextRoomDoor.AisleFloorCell = floorCell;
                roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);;
                nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
                return true;
            }
        }
        
        return false;
    }

    /// <summary>
    /// 尝试寻找横轴方向上两个房间的连通的门, 只查找直线通道, 返回是否找到
    /// </summary>
    private bool TryConnectHorizontalDoor(RoomInfo roomInfo, RoomDoorInfo roomDoor, RoomInfo nextRoomInfo, RoomDoorInfo nextRoomDoor)
    {
        var overlapY = Mathf.Min(roomInfo.GetVerticalEnd(), nextRoomInfo.GetVerticalEnd()) -
                       Mathf.Max(roomInfo.GetVerticalStart(), nextRoomInfo.GetVerticalStart());
        //这种情况下y轴有重叠
        if (overlapY >= 6)
        {
            //填充通通道地板格子
            var floorCell = new HashSet<Vector2I>();
            
            //找到重叠区域
            var rangeList = FindPassage(roomInfo, nextRoomInfo, 
                roomInfo.GetHorizontalStart() < nextRoomInfo.GetHorizontalStart() ? DoorDirection.E : DoorDirection.W);

            while (rangeList.Count > 0)
            {
                //找到重叠区域
                var range = Random.RandomChooseAndRemove(rangeList);
                var y = Random.RandomRangeInt(range.X, range.Y) + 3;
                
                if (roomInfo.GetHorizontalStart() < nextRoomInfo.GetHorizontalStart()) //room在左, nextRoom在右
                {
                    roomDoor.Direction = DoorDirection.E;
                    nextRoomDoor.Direction = DoorDirection.W;
                    roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorEnd(), y);
                    nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart(), y);

                    var sv = roomInfo.GetHorizontalDoorEnd() - 1;
                    var ev = nextRoomInfo.GetHorizontalDoorStart() + 1;
                    for (var i = sv; i < ev; i++)
                    {
                        floorCell.Add(new Vector2I(i, y + 2));
                    }
                }
                else //room在右, nextRoom在左
                {
                    roomDoor.Direction = DoorDirection.W;
                    nextRoomDoor.Direction = DoorDirection.E;
                    roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart(), y);
                    nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorEnd(), y);

                    var sv = nextRoomInfo.GetHorizontalDoorEnd() - 1;
                    var ev = roomInfo.GetHorizontalDoorStart() + 1;
                    for (var i = sv; i < ev; i++)
                    {
                        floorCell.Add(new Vector2I(i, y + 2));
                    }
                }

                //判断门之间的通道是否有物体碰到
                if (!AddCorridorToGridRange(roomDoor, nextRoomDoor))
                {
                    //此门不能连通
                    floorCell.Clear();
                    continue;
                }

                //没有撞到物体
                roomInfo.Doors.Add(roomDoor);
                nextRoomInfo.Doors.Add(nextRoomDoor);
                
                roomDoor.AisleFloorCell = floorCell;
                nextRoomDoor.AisleFloorCell = floorCell;
                roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);;
                nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 尝试寻找包含拐角的两个房间的连通的门, 返回是否找到
    /// </summary>
    private bool TryConnectCrossDoor(RoomInfo roomInfo, RoomDoorInfo roomDoor, RoomInfo nextRoomInfo, RoomDoorInfo nextRoomDoor)
    {
        //焦点
        Vector2I cross = default;

        if (roomInfo.GetHorizontalStart() > nextRoomInfo.GetHorizontalStart())
        {
            if (roomInfo.GetVerticalStart() > nextRoomInfo.GetVerticalStart())
            {
                if (Random.RandomBoolean()) //↑ //→
                {
                    if (!TryConnect_NE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
                        !TryConnect_WS_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
                    {
                        return false;
                    }
                }
                else //← //↓
                {
                    if (!TryConnect_WS_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
                        !TryConnect_NE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
                    {
                        return false;
                    }
                }
            }
            else
            {
                if (Random.RandomBoolean()) //↓ //→
                {
                    if (!TryConnect_SE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
                        !TryConnect_WN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
                    {
                        return false;
                    }
                }
                else //← //↑
                {
                    if (!TryConnect_WN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
                        !TryConnect_SE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
                    {
                        return false;
                    }
                }
            }
        }
        else
        {
            if (roomInfo.GetVerticalStart() > nextRoomInfo.GetVerticalStart()) //→ //↓
            {
                if (Random.RandomBoolean())
                {
                    if (!TryConnect_ES_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
                        !TryConnect_NW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
                    {
                        return false;
                    }
                }
                else //↑ //←
                {
                    if (!TryConnect_NW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
                        !TryConnect_ES_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
                    {
                        return false;
                    }
                }
            }
            else
            {
                if (Random.RandomBoolean()) //→ //↑
                {
                    if (!TryConnect_EN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
                        !TryConnect_SW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
                    {
                        return false;
                    }
                }
                else //↓ //←
                {
                    if (!TryConnect_SW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
                        !TryConnect_EN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
                    {
                        return false;
                    }
                }
            }
        }

        //判断门之间的通道是否有物体碰到
        if (!AddCorridorToGridRange(roomDoor, nextRoomDoor, cross))
        {
            //此门不能连通
            return false;
        }

        roomDoor.HasCross = true;
        roomDoor.Cross = cross;
        nextRoomDoor.HasCross = true;
        nextRoomDoor.Cross = cross;

        roomInfo.Doors.Add(roomDoor);
        nextRoomInfo.Doors.Add(nextRoomDoor);
        return true;
    }

    private bool FindCrossPassage(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor,ref int offset1, ref int offset2)
    {
        var room1 = roomInfo.RoomSplit.RoomInfo;
        var room2 = nextRoomInfo.RoomSplit.RoomInfo;
        
        int? temp1 = null;
        int? temp2 = null;

        foreach (var areaInfo1 in room1.GetCompletionDoorArea())
        {
            if (areaInfo1.Direction == roomDoor.Direction)
            {
                FindCrossPassage_Area(areaInfo1, roomInfo, nextRoomInfo, ref temp1);
            }
        }
        
        if (temp1 == null)
        {
            return false;
        }

        foreach (var areaInfo2 in room2.GetCompletionDoorArea())
        {
            if (areaInfo2.Direction == nextRoomDoor.Direction)
            {
                FindCrossPassage_Area(areaInfo2, nextRoomInfo, roomInfo, ref temp2);
            }
        }

        if (temp2 == null)
        {
            return false;
        }
        
        offset1 = temp1.Value;
        offset2 = temp2.Value;
        return true;
    }

    private void FindCrossPassage_Area(DoorAreaInfo areaInfo, RoomInfo room1, RoomInfo room2, ref int? areaRange)
    {
        if (areaInfo.Direction == DoorDirection.N || areaInfo.Direction == DoorDirection.S) //纵向门
        {
            var num = room1.GetHorizontalStart();
            var p1 = num + GetDoorAreaInfoStart(areaInfo) / GameConfig.TileCellSize;
            var p2 = num + GetDoorAreaInfoEnd(areaInfo) / GameConfig.TileCellSize;

            if (room1.Position.X > room2.Position.X)
            {
                var range = CalcOverlapRange(room2.GetHorizontalEnd() + GameConfig.RoomSpace,
                    room1.GetHorizontalEnd(), p1, p2);
                //交集范围够生成门
                if (range.Y - range.X >= GameConfig.CorridorWidth)
                {
                    // var tempRange = new Vector2I(Mathf.Abs(room1.Position.X - (int)range.X),
                    //     Mathf.Abs(room1.Position.X - (int)range.Y) - GameConfig.CorridorWidth);
                    
                    var rangeValue = Mathf.Abs(room1.Position.X - (int)range.X);

                    if (areaRange == null || rangeValue < areaRange)
                    {
                        areaRange = rangeValue;
                    }
                }
            }
            else
            {
                var range = CalcOverlapRange(room1.GetHorizontalStart(),
                    room2.GetHorizontalStart() -  + GameConfig.RoomSpace, p1, p2);
                //交集范围够生成门
                if (range.Y - range.X >= GameConfig.CorridorWidth)
                {
                    // var tempRange = new Vector2I(Mathf.Abs(room1.Position.X - (int)range.X),
                    //     Mathf.Abs(room1.Position.X - (int)range.Y) - GameConfig.CorridorWidth);

                    var rangeValue = Mathf.Abs(room1.Position.X - (int)range.Y) - GameConfig.CorridorWidth;

                    if (areaRange == null || rangeValue > areaRange)
                    {
                        areaRange = rangeValue;
                    }
                }
            }
        }
        else //横向门
        {
            var num = room1.GetVerticalStart();
            var p1 = num + GetDoorAreaInfoStart(areaInfo) / GameConfig.TileCellSize;
            var p2 = num + GetDoorAreaInfoEnd(areaInfo) / GameConfig.TileCellSize;

            if (room1.Position.Y > room2.Position.Y)
            {
                var range = CalcOverlapRange(room2.GetVerticalEnd() + GameConfig.RoomSpace,
                    room1.GetVerticalEnd(), p1, p2);
                //交集范围够生成门
                if (range.Y - range.X >= GameConfig.CorridorWidth)
                {
                    // var tempRange = new Vector2I(Mathf.Abs(room1.Position.Y - (int)range.X),
                    //     Mathf.Abs(room1.Position.Y - (int)range.Y) - GameConfig.CorridorWidth);

                    var rangeValue = Mathf.Abs(room1.Position.Y - (int)range.X);

                    if (areaRange == null || rangeValue < areaRange)
                    {
                        areaRange = rangeValue;
                    }
                }
            }
            else
            {
                var range = CalcOverlapRange(room1.GetVerticalStart(),
                    room2.GetVerticalStart() - GameConfig.RoomSpace, p1, p2);
                //交集范围够生成门
                if (range.Y - range.X >= GameConfig.CorridorWidth)
                {
                    // var tempRange = new Vector2I(Mathf.Abs(room1.Position.Y - (int)range.X),
                    //     Mathf.Abs(room1.Position.Y - (int)range.Y) - GameConfig.CorridorWidth);
                    
                    var rangeValue = Mathf.Abs(room1.Position.Y - (int)range.Y) - GameConfig.CorridorWidth;

                    if (areaRange == null || rangeValue > areaRange)
                    {
                        areaRange = rangeValue;
                    }
                }
            }
        }
    }

    private bool TryConnect_NE_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
    {
        var offset1 = 0;
        var offset2 = 0;
        roomDoor.Direction = DoorDirection.N; //↑
        nextRoomDoor.Direction = DoorDirection.E; //→

        if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
        {
            return false;
        }

        offset1 += 1;
        offset2 += 1;
        roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart() + offset1, roomInfo.GetVerticalDoorStart());
        nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorEnd(), nextRoomInfo.GetVerticalDoorStart() + offset2);
        cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);

        var floorCell = new HashSet<Vector2I>();

        //纵轴地板
        for (var y = cross.Y + 3; y <= roomDoor.OriginPosition.Y; y++)
        {
            floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 1, y));
            floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 2, y));
        }
        //横轴地板
        for (var x = nextRoomDoor.OriginPosition.X - 1; x <= cross.X; x++)
        {
            floorCell.Add(new Vector2I(x, nextRoomDoor.OriginPosition.Y + 2));
        }
        //交叉点地板
        floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
        floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
        
        roomDoor.AisleFloorCell = floorCell;
        nextRoomDoor.AisleFloorCell = floorCell;
        roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
        nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
        return true;
    }

    private bool TryConnect_WS_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
    {
        var offset1 = 0;
        var offset2 = 0;
        roomDoor.Direction = DoorDirection.W; //←
        nextRoomDoor.Direction = DoorDirection.S; //↓
                
        if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
        {
            return false;
        }

        offset1 += 1;
        offset2 += 1;
        roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart(), roomInfo.GetVerticalDoorStart() + offset1);
        nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart() + offset2, nextRoomInfo.GetVerticalDoorEnd());
        cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
        
        var floorCell = new HashSet<Vector2I>();

        //横轴地板
        for (var x = cross.X + 3; x <= roomDoor.OriginPosition.X; x++)
        {
            floorCell.Add(new Vector2I(x, roomDoor.OriginPosition.Y + 2));
        }
        //纵轴地板
        for (var y = nextRoomDoor.OriginPosition.Y - 1; y <= cross.Y + 1; y++)
        {
            floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 1, y));
            floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 2, y));
        }

        //交叉点地板
        floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
        floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
        
        roomDoor.AisleFloorCell = floorCell;
        nextRoomDoor.AisleFloorCell = floorCell;
        roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
        nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
        return true;
    }

    private bool TryConnect_SE_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
    {
        var offset1 = 0;
        var offset2 = 0;
        roomDoor.Direction = DoorDirection.S; //↓
        nextRoomDoor.Direction = DoorDirection.E; //→
                    
        if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
        {
            return false;
        }

        offset1 += 1;
        offset2 += 1;
        roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart() + offset1, roomInfo.GetVerticalDoorEnd());
        nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorEnd(), nextRoomInfo.GetVerticalDoorStart() + offset2);
        cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
        
        var floorCell = new HashSet<Vector2I>();
        
        //纵轴地板
        for (var y = roomDoor.OriginPosition.Y - 1; y <= cross.Y + 1; y++)
        {
            floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 1, y));
            floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 2, y));
        }
        
        //横轴地板
        for (var x = nextRoomDoor.OriginPosition.X - 1; x <= cross.X; x++)
        {
            floorCell.Add(new Vector2I(x, nextRoomDoor.OriginPosition.Y + 2));
        }
        
        //交叉点地板
        floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
        floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
        
        roomDoor.AisleFloorCell = floorCell;
        nextRoomDoor.AisleFloorCell = floorCell;
        roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
        nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
        return true;
    }

    private bool TryConnect_WN_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
    {
        var offset1 = 0;
        var offset2 = 0;
        roomDoor.Direction = DoorDirection.W; //←
        nextRoomDoor.Direction = DoorDirection.N; //↑
                    
        if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
        {
            return false;
        }

        offset1 += 1;
        offset2 += 1;
        roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart(), roomInfo.GetVerticalDoorStart() + offset1); //
        nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart() + offset2, nextRoomInfo.GetVerticalDoorStart());
        cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
        
        var floorCell = new HashSet<Vector2I>();
        
        //横轴地板
        for (var x = cross.X + 3; x <= roomDoor.OriginPosition.X; x++)
        {
            floorCell.Add(new Vector2I(x, roomDoor.OriginPosition.Y + 2));
        }
        
        //纵轴地板
        for (var y = cross.Y + 3; y <= nextRoomDoor.OriginPosition.Y; y++)
        {
            floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 1, y));
            floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 2, y));
        }
        
        //交叉点地板
        floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
        floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
        
        roomDoor.AisleFloorCell = floorCell;
        nextRoomDoor.AisleFloorCell = floorCell;
        roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
        nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
        return true;
    }
    
    private bool TryConnect_ES_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
    {
        var offset1 = 0;
        var offset2 = 0;
        roomDoor.Direction = DoorDirection.E; //→
        nextRoomDoor.Direction = DoorDirection.S; //↓

        if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
        {
            return false;
        }

        offset1 += 1;
        offset2 += 1;
        roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorEnd(), roomInfo.GetVerticalDoorStart() + offset1);
        nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart() + offset2, nextRoomInfo.GetVerticalDoorEnd());
        cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
        
        var floorCell = new HashSet<Vector2I>();
        
        //横轴地板
        for (var x = roomDoor.OriginPosition.X - 1; x <= cross.X; x++)
        {
            floorCell.Add(new Vector2I(x, roomDoor.OriginPosition.Y + 2));
        }
        
        //纵轴地板
        for (var y = nextRoomDoor.OriginPosition.Y - 1; y <= cross.Y + 1; y++)
        {
            floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 1, y));
            floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 2, y));
        }
        
        //交叉点地板
        floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
        floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
        
        roomDoor.AisleFloorCell = floorCell;
        nextRoomDoor.AisleFloorCell = floorCell;
        roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
        nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
        return true;
    }
    
    private bool TryConnect_NW_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
    {
        var offset1 = 0;
        var offset2 = 0;
        roomDoor.Direction = DoorDirection.N; //↑
        nextRoomDoor.Direction = DoorDirection.W; //←

        if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
        {
            return false;
        }

        offset1 += 1;
        offset2 += 1;
        roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart() + offset1, roomInfo.GetVerticalDoorStart());
        nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart(), nextRoomInfo.GetVerticalDoorStart() + offset2);
        cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
        
        var floorCell = new HashSet<Vector2I>();
        
        //纵轴地板
        for (var y = cross.Y + 3; y <= roomDoor.OriginPosition.Y; y++)
        {
            floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 1, y));
            floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 2, y));
        }
        
        //横轴地板
        for (var x = cross.X + 3; x <= nextRoomDoor.OriginPosition.X; x++)
        {
            floorCell.Add(new Vector2I(x, nextRoomDoor.OriginPosition.Y + 2));
        }
        
        //交叉点地板
        floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
        floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
        
        roomDoor.AisleFloorCell = floorCell;
        nextRoomDoor.AisleFloorCell = floorCell;
        roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
        nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
        return true;
    }
    
    private bool TryConnect_EN_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
    {
        var offset1 = 0;
        var offset2 = 0;
        roomDoor.Direction = DoorDirection.E; //→
        nextRoomDoor.Direction = DoorDirection.N; //↑

        if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
        {
            return false;
        }
        
        offset1 += 1;
        offset2 += 2;
        roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorEnd(), roomInfo.GetVerticalDoorStart() + offset1);
        nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalStart() + offset2, nextRoomInfo.GetVerticalDoorStart());
        cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
        
        var floorCell = new HashSet<Vector2I>();
        
        //横轴地板
        for (var x = roomDoor.OriginPosition.X - 1; x <= cross.X; x++)
        {
            floorCell.Add(new Vector2I(x, roomDoor.OriginPosition.Y + 2));
        }
        
        //纵轴地板
        for (var y = cross.Y + 3; y <= nextRoomDoor.OriginPosition.Y; y++)
        {
            floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 1, y));
            floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 2, y));
        }
        
        //交叉点地板
        floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
        floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
        
        roomDoor.AisleFloorCell = floorCell;
        nextRoomDoor.AisleFloorCell = floorCell;
        roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
        nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
        return true;
    }

    private bool TryConnect_SW_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
    {
        var offset1 = 0;
        var offset2 = 0;
        roomDoor.Direction = DoorDirection.S; //↓
        nextRoomDoor.Direction = DoorDirection.W; //←

        if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
        {
            return false;
        }

        offset1 += 1;
        offset2 += 1;
        roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart() + offset1, roomInfo.GetVerticalDoorEnd());
        nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart(), nextRoomInfo.GetVerticalDoorStart() + offset2);
        cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
        
        var floorCell = new HashSet<Vector2I>();
        
        //纵轴地板
        for (var y = roomDoor.OriginPosition.Y - 1; y <= cross.Y + 1; y++)
        {
            floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 1, y));
            floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 2, y));
        }
        
        //横轴地板
        for (var x = cross.X + 3; x <= nextRoomDoor.OriginPosition.X; x++)
        {
            floorCell.Add(new Vector2I(x, nextRoomDoor.OriginPosition.Y + 2));
        }
        
        //交叉点地板
        floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
        floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
        
        roomDoor.AisleFloorCell = floorCell;
        nextRoomDoor.AisleFloorCell = floorCell;
        roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
        nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
        return true;
    }

    /// <summary>
    /// 查找房间的连接通道, 函数返回是否找到对应的门, 通过 result 返回 x/y 轴坐标
    /// </summary>
    /// <param name="roomInfo">第一个房间</param>
    /// <param name="nextRoomInfo">第二个房间</param>
    /// <param name="direction">第一个房间连接方向</param>
    private List<Vector2I> FindPassage(RoomInfo roomInfo, RoomInfo nextRoomInfo, DoorDirection direction)
    {
        var room1 = roomInfo.RoomSplit.RoomInfo;
        var room2 = nextRoomInfo.RoomSplit.RoomInfo;
        
        //用于存储符合生成条件的区域
        var rangeList = new List<Vector2I>();
        
        foreach (var doorAreaInfo1 in room1.GetCompletionDoorArea())
        {
            if (doorAreaInfo1.Direction == direction)
            {
                //第二个门的方向
                var direction2 = GetReverseDirection(direction);
                
                foreach (var doorAreaInfo2 in room2.GetCompletionDoorArea())
                {
                    if (doorAreaInfo2.Direction == direction2)
                    {
                        Vector2 range;
                        if (direction == DoorDirection.E || direction == DoorDirection.W) //第二个门向← 或者 第二个门向→
                        {
                            range = CalcOverlapRange(
                                roomInfo.GetVerticalStart() * GameConfig.TileCellSize + GetDoorAreaInfoStart(doorAreaInfo1), roomInfo.GetVerticalStart() * GameConfig.TileCellSize + GetDoorAreaInfoEnd(doorAreaInfo1),
                                nextRoomInfo.GetVerticalStart() * GameConfig.TileCellSize + GetDoorAreaInfoStart(doorAreaInfo2), nextRoomInfo.GetVerticalStart() * GameConfig.TileCellSize + GetDoorAreaInfoEnd(doorAreaInfo2)
                            );
                        }
                        else //第二个门向↑ 或者 第二个门向↓
                        {
                            range = CalcOverlapRange(
                                roomInfo.GetHorizontalStart() * GameConfig.TileCellSize + GetDoorAreaInfoStart(doorAreaInfo1), roomInfo.GetHorizontalStart() * GameConfig.TileCellSize + GetDoorAreaInfoEnd(doorAreaInfo1),
                                nextRoomInfo.GetHorizontalStart() * GameConfig.TileCellSize + GetDoorAreaInfoStart(doorAreaInfo2), nextRoomInfo.GetHorizontalStart() * GameConfig.TileCellSize + GetDoorAreaInfoEnd(doorAreaInfo2)
                            );
                        }
                        //交集范围够生成门
                        if (range.Y - range.X >= GameConfig.CorridorWidth * GameConfig.TileCellSize)
                        {
                            rangeList.Add(new Vector2I((int)(range.X / GameConfig.TileCellSize), (int)(range.Y / GameConfig.TileCellSize) - GameConfig.CorridorWidth));
                        }
                    }
                }
            }
        }
        
        return rangeList;
    }
    
    /// <summary>
    /// 用于计算重叠区域坐标, 可以理解为一维轴上4个点的中间两个点, 返回的x为起始点, y为结束点
    /// </summary>
    private Vector2 CalcOverlapRange(float start1, float end1, float start2, float end2)
    {
        return new Vector2(Mathf.Max(start1, start2), Mathf.Min(end1, end2));
    }

    /// <summary>
    /// 返回 p1 - p2 是否在 start - end 范围内
    /// </summary>
    private bool IsInRange(float start, float end, float p1, float p2)
    {
        return p1 >= start && p2 <= end;
    }
    
    //返回指定方向的反方向
    //0上, 1右, 2下, 3左
    private int GetReverseDirection(int direction)
    {
        switch (direction)
        {
            case 0: return 2;
            case 1: return 3;
            case 2: return 0;
            case 3: return 1;
        }

        return 2;
    }
    
    //返回参数方向的反方向
    private DoorDirection GetReverseDirection(DoorDirection direction)
    {
        switch (direction)
        {
            case DoorDirection.E:
                return DoorDirection.W;
            case DoorDirection.W:
                return DoorDirection.E;
            case DoorDirection.S:
                return DoorDirection.N;
            case DoorDirection.N:
                return DoorDirection.S;
        }

        return DoorDirection.S;
    }

    //将两个门间的过道占用数据存入RoomGrid
    private bool AddCorridorToGridRange(RoomDoorInfo door1, RoomDoorInfo door2)
    {
        var point1 = door1.OriginPosition;
        var point2 = door2.OriginPosition;
        var pos = new Vector2I(Mathf.Min(point1.X, point2.X), Mathf.Min(point1.Y, point2.Y));
        var size = new Vector2I(
            point1.X == point2.X ? GameConfig.CorridorWidth : Mathf.Abs(point1.X - point2.X),
            point1.Y == point2.Y ? GameConfig.CorridorWidth : Mathf.Abs(point1.Y - point2.Y)
        );

        Vector2I collPos;
        Vector2I collSize;
        if (point1.X == point2.X) //纵向加宽, 防止贴到其它墙
        {
            pos.Y += 1;
            size.Y -= 3;
            collPos = new Vector2I(pos.X - GameConfig.RoomSpace, pos.Y);
            collSize = new Vector2I(size.X + GameConfig.RoomSpace * 2, size.Y);
        }
        else //横向加宽, 防止贴到其它墙
        {
            pos.X += 1;
            size.X -= 2;
            collPos = new Vector2I(pos.X, pos.Y - GameConfig.RoomSpace);
            collSize = new Vector2I(size.X, size.Y + GameConfig.RoomSpace * 2);
        }

        if (_roomGrid.RectCollision(collPos, collSize))
        {
            return false;
        }

        door2.RoomInfo.AisleArea.Add(new Rect2I(pos, size));
        _roomGrid.SetRect(pos, size, true);
        return true;
    }

    //将两个门间的过道占用数据存入RoomGrid, 该重载加入拐角点
    private bool AddCorridorToGridRange(RoomDoorInfo door1, RoomDoorInfo door2, Vector2I cross)
    {
        if (_roomGrid.RectCollision(cross - new Vector2I(1, 2), new Vector2I(GameConfig.CorridorWidth + 2, GameConfig.CorridorWidth + 3)))
        {
            return false;
        }
        
        var point1 = door1.OriginPosition;
        var point2 = door2.OriginPosition;
        var pos1 = new Vector2I(Mathf.Min(point1.X, cross.X), Mathf.Min(point1.Y, cross.Y));
        var size1 = new Vector2I(
            point1.X == cross.X ? GameConfig.CorridorWidth : Mathf.Abs(point1.X - cross.X),
            point1.Y == cross.Y ? GameConfig.CorridorWidth : Mathf.Abs(point1.Y - cross.Y)
        );
        var pos2 = new Vector2I(Mathf.Min(point2.X, cross.X), Mathf.Min(point2.Y, cross.Y));
        var size2 = new Vector2I(
            point2.X == cross.X ? GameConfig.CorridorWidth : Mathf.Abs(point2.X - cross.X),
            point2.Y == cross.Y ? GameConfig.CorridorWidth : Mathf.Abs(point2.Y - cross.Y)
        );

        Vector2I collPos1;
        Vector2I collSize1;
        if (point1.X == cross.X) //纵向加宽, 防止贴到其它墙
        {
            if (door1.Direction == DoorDirection.N)
            {
                size1.Y -= 2;
            }
            else
            {
                pos1.Y += 1;
                size1.Y -= 1;
            }
            collPos1 = new Vector2I(pos1.X - GameConfig.RoomSpace, pos1.Y);
            collSize1 = new Vector2I(size1.X + GameConfig.RoomSpace * 2, size1.Y);
        }
        else //横向加宽, 防止贴到其它墙
        {
            if (door1.Direction == DoorDirection.E)
            {
                pos1.X += 1;
                size1.X -= 1;
            }
            else
            {
                size1.X -= 1;
            }
            collPos1 = new Vector2I(pos1.X, pos1.Y - GameConfig.RoomSpace);
            collSize1 = new Vector2I(size1.X, size1.Y + GameConfig.RoomSpace * 2);
        }

        if (_roomGrid.RectCollision(collPos1, collSize1))
        {
            return false;
        }

        Vector2I collPos2;
        Vector2I collSize2;
        if (point2.X == cross.X) //纵向加宽, 防止贴到其它墙
        {
            if (door2.Direction == DoorDirection.N)
            {
                size2.Y -= 2;
            }
            else
            {
                pos2.Y += 1;
                size2.Y -= 1;
            }
            collPos2 = new Vector2I(pos2.X - GameConfig.RoomSpace, pos2.Y);
            collSize2 = new Vector2I(size2.X + GameConfig.RoomSpace * 2, size2.Y);
        }
        else //横向加宽, 防止贴到其它墙
        {
            if (door2.Direction == DoorDirection.E)
            {
                pos2.X += 1;
                size2.X -= 1;
            }
            else
            {
                size2.X -= 1;
            }
            collPos2 = new Vector2I(pos2.X, pos2.Y - GameConfig.RoomSpace);
            collSize2 = new Vector2I(size2.X, size2.Y + GameConfig.RoomSpace * 2);
        }

        if (_roomGrid.RectCollision(collPos2, collSize2))
        {
            return false;
        }

        door2.RoomInfo.AisleArea.Add(new Rect2I(pos1, size1));
        door2.RoomInfo.AisleArea.Add(new Rect2I(pos2, size2));
        _roomGrid.SetRect(pos1, size1, true);
        _roomGrid.SetRect(pos2, size2, true);
        return true;
    }

    private int GetDoorAreaInfoStart(DoorAreaInfo areaInfo)
    {
        return areaInfo.Start;
    }

    private int GetDoorAreaInfoEnd(DoorAreaInfo areaInfo)
    {
        return areaInfo.End;
    }
}