Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / DungeonGenerator.cs
  1.  
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using Godot;
  6.  
  7. /// <summary>
  8. /// 地牢生成器
  9. /// </summary>
  10. public class DungeonGenerator
  11. {
  12. /// <summary>
  13. /// 所有生成的房间, 调用过 Generate() 函数才能获取到值
  14. /// </summary>
  15. public List<RoomInfo> RoomInfos { get; } = new List<RoomInfo>();
  16.  
  17. /// <summary>
  18. /// 起始房间
  19. /// </summary>
  20. public RoomInfo StartRoomInfo { get; private set; }
  21.  
  22. /// <summary>
  23. /// 战斗房间
  24. /// </summary>
  25. public List<RoomInfo> BattleRoomInfos { get; } = new List<RoomInfo>();
  26. /// <summary>
  27. /// 结束房间
  28. /// </summary>
  29. public List<RoomInfo> EndRoomInfos { get; } = new List<RoomInfo>();
  30.  
  31. /// <summary>
  32. /// boss房间
  33. /// </summary>
  34. public List<RoomInfo> BossRoomInfos { get; } = new List<RoomInfo>();
  35. /// <summary>
  36. /// 奖励房间
  37. /// </summary>
  38. public List<RoomInfo> RewardRoomInfos { get; } = new List<RoomInfo>();
  39.  
  40. /// <summary>
  41. /// 商店房间
  42. /// </summary>
  43. public List<RoomInfo> ShopRoomInfos { get; } = new List<RoomInfo>();
  44. /// <summary>
  45. /// 地牢配置数据
  46. /// </summary>
  47. public DungeonConfig Config { get; }
  48. /// <summary>
  49. /// 所属地牢组
  50. /// </summary>
  51. public DungeonRoomGroup RoomGroup { get; }
  52.  
  53. /// <summary>
  54. /// 随机数对象
  55. /// </summary>
  56. public SeedRandom Random;
  57.  
  58. //用于标记地图上的坐标是否被占用
  59. private InfiniteGrid<bool> _roomGrid { get; } = new InfiniteGrid<bool>();
  60. //房间id
  61. private int _id;
  62. //下一个房间类型
  63. private DungeonRoomType _nextRoomType = DungeonRoomType.None;
  64. //区域限制
  65. private int _rangeX = 120;
  66. private int _rangeY = 120;
  67. //找房间失败次数, 过大则会关闭区域限制
  68. private int _maxFailCount = 10;
  69. private int _failCount = 0;
  70.  
  71. //最大尝试次数
  72. private int _maxTryCount = 10;
  73. private int _currMaxLayer = 0;
  74.  
  75. //地牢房间规则处理类
  76. private DungeonRule _rule;
  77. //上一个房间
  78. private RoomInfo prevRoomInfo = null;
  79. private readonly List<RoomInfo> _tempList = new List<RoomInfo>();
  80. public DungeonGenerator(DungeonConfig config, SeedRandom seedRandom)
  81. {
  82. Config = config;
  83. Random = seedRandom;
  84. RoomGroup = GameApplication.Instance.RoomConfig[config.GroupName];
  85. _rangeX = config.RangeX;
  86. _rangeY = config.RangeY;
  87.  
  88. //验证该组是否满足生成地牢的条件
  89. var result = DungeonManager.CheckDungeon(config.GroupName);
  90. if (result.HasError)
  91. {
  92. throw new Exception("当前组'" + config.GroupName + "'" + result.ErrorMessage + ", 不能生成地牢!");
  93. }
  94. Debug.Log("创建地牢生成器, 随机种子: " + Random.Seed);
  95. RoomGroup.InitWeight(Random);
  96. }
  97.  
  98. /// <summary>
  99. /// 遍历所有房间
  100. /// </summary>
  101. public void EachRoom(Action<RoomInfo> cb)
  102. {
  103. EachRoom(StartRoomInfo, cb);
  104. }
  105.  
  106. private void EachRoom(RoomInfo roomInfo, Action<RoomInfo> cb)
  107. {
  108. if (roomInfo == null)
  109. {
  110. return;
  111. }
  112.  
  113. cb(roomInfo);
  114. foreach (var next in roomInfo.Next)
  115. {
  116. EachRoom(next, cb);
  117. }
  118. }
  119. /// <summary>
  120. /// 用于协程中的遍历所有房间
  121. /// </summary>
  122. public IEnumerator EachRoomCoroutine(Action<RoomInfo> cb)
  123. {
  124. return EachRoomCoroutine(StartRoomInfo, cb);
  125. }
  126. private IEnumerator EachRoomCoroutine(RoomInfo roomInfo, Action<RoomInfo> cb)
  127. {
  128. if (roomInfo == null)
  129. {
  130. yield break;
  131. }
  132.  
  133. cb(roomInfo);
  134. foreach (var next in roomInfo.Next)
  135. {
  136. yield return EachRoomCoroutine(next, cb);
  137. }
  138. }
  139.  
  140. /// <summary>
  141. /// 生成房间
  142. /// </summary>
  143. public bool Generate(DungeonRule rule)
  144. {
  145. if (StartRoomInfo != null) return false;
  146. _rule = rule;
  147. //最大尝试次数
  148. var maxTryCount = 1000;
  149.  
  150. //当前尝试次数
  151. var currTryCount = 0;
  152.  
  153. if (Config.HasDesignatedRoom) //指定房间列表
  154. {
  155. for (var i = 0; i < Config.DesignatedRoom.Count; i++)
  156. {
  157. var roomSplit = Config.DesignatedRoom[i];
  158. var nextRoomType = roomSplit.RoomInfo.RoomType;
  159. var errorCode = GenerateRoom(prevRoomInfo, roomSplit.RoomInfo.RoomType, out var nextRoom);
  160. if (errorCode == GenerateRoomErrorCode.NoError) //生成成功
  161. {
  162. _failCount = 0;
  163. RoomInfos.Add(nextRoom);
  164. if (nextRoomType == DungeonRoomType.Inlet)
  165. {
  166. StartRoomInfo = nextRoom;
  167. }
  168. else if (nextRoomType == DungeonRoomType.Boss) //boss房间
  169. {
  170. BossRoomInfos.Add(nextRoom);
  171. }
  172. else if (nextRoomType == DungeonRoomType.Outlet)
  173. {
  174. EndRoomInfos.Add(nextRoom);
  175. }
  176. else if (nextRoomType == DungeonRoomType.Battle)
  177. {
  178. BattleRoomInfos.Add(nextRoom);
  179. }
  180. else if (nextRoomType == DungeonRoomType.Reward)
  181. {
  182. RewardRoomInfos.Add(nextRoom);
  183. }
  184. else if (nextRoomType == DungeonRoomType.Shop)
  185. {
  186. ShopRoomInfos.Add(nextRoom);
  187. }
  188.  
  189. prevRoomInfo = nextRoom;
  190. }
  191. else //生成失败
  192. {
  193. //Debug.Log("生成第" + (_count + 1) + "个房间失败! 失败原因: " + errorCode);
  194. if (errorCode == GenerateRoomErrorCode.OutArea)
  195. {
  196. _failCount++;
  197. Debug.Log("超出区域失败次数: " + _failCount);
  198. if (_failCount >= _maxFailCount)
  199. {
  200. //_enableLimitRange = false;
  201. _failCount = 0;
  202. _rangeX += 50;
  203. _rangeY += 50;
  204. Debug.Log("生成房间失败次数过多, 增大区域");
  205. }
  206. }
  207.  
  208. currTryCount++;
  209. if (currTryCount >= maxTryCount)
  210. {
  211. return false;
  212. }
  213.  
  214. i--;
  215. }
  216. }
  217. }
  218. else //正常随机生成
  219. {
  220. //如果房间数量不够, 就一直生成
  221. while (!_rule.CanOverGenerator())
  222. {
  223. if (_nextRoomType == DungeonRoomType.None)
  224. {
  225. _nextRoomType = _rule.GetNextRoomType(prevRoomInfo);
  226. }
  227.  
  228. var nextRoomType = _nextRoomType;
  229.  
  230. //上一个房间
  231. var tempPrevRoomInfo = _rule.GetConnectPrevRoom(prevRoomInfo, nextRoomType);
  232. //生成下一个房间
  233. var errorCode = GenerateRoom(tempPrevRoomInfo, nextRoomType, out var nextRoom);
  234. if (errorCode == GenerateRoomErrorCode.NoError) //生成成功
  235. {
  236. _failCount = 0;
  237. RoomInfos.Add(nextRoom);
  238. if (nextRoomType == DungeonRoomType.Inlet)
  239. {
  240. StartRoomInfo = nextRoom;
  241. }
  242. else if (nextRoomType == DungeonRoomType.Boss) //boss房间
  243. {
  244. BossRoomInfos.Add(nextRoom);
  245. }
  246. else if (nextRoomType == DungeonRoomType.Outlet)
  247. {
  248. EndRoomInfos.Add(nextRoom);
  249. }
  250. else if (nextRoomType == DungeonRoomType.Battle)
  251. {
  252. BattleRoomInfos.Add(nextRoom);
  253. }
  254. else if (nextRoomType == DungeonRoomType.Reward)
  255. {
  256. RewardRoomInfos.Add(nextRoom);
  257. }
  258. else if (nextRoomType == DungeonRoomType.Shop)
  259. {
  260. ShopRoomInfos.Add(nextRoom);
  261. }
  262.  
  263. prevRoomInfo = nextRoom;
  264. _rule.GenerateRoomSuccess(tempPrevRoomInfo, nextRoom);
  265. _nextRoomType = _rule.GetNextRoomType(nextRoom);
  266. }
  267. else //生成失败
  268. {
  269. _rule.GenerateRoomFail(tempPrevRoomInfo, nextRoomType);
  270.  
  271. //Debug.Log("生成第" + (_count + 1) + "个房间失败! 失败原因: " + errorCode);
  272. if (errorCode == GenerateRoomErrorCode.OutArea)
  273. {
  274. _failCount++;
  275. Debug.Log("超出区域失败次数: " + _failCount);
  276. if (_failCount >= _maxFailCount)
  277. {
  278. //_enableLimitRange = false;
  279. _failCount = 0;
  280. _rangeX += 50;
  281. _rangeY += 50;
  282. Debug.Log("生成房间失败次数过多, 增大区域");
  283. }
  284. }
  285.  
  286. currTryCount++;
  287. if (currTryCount >= maxTryCount)
  288. {
  289. return false;
  290. }
  291. }
  292. }
  293. }
  294.  
  295. _roomGrid.Clear();
  296. Debug.Log("房间总数: " + RoomInfos.Count);
  297. Debug.Log("尝试次数: " + currTryCount);
  298. return true;
  299. }
  300.  
  301. //生成房间
  302. private GenerateRoomErrorCode GenerateRoom(RoomInfo prevRoom, DungeonRoomType roomType, out RoomInfo resultRoomInfo)
  303. {
  304. // if (_count >= _config.RoomCount)
  305. // {
  306. // resultRoom = null;
  307. // return GenerateRoomErrorCode.RoomFull;
  308. // }
  309.  
  310. DungeonRoomSplit roomSplit;
  311. if (Config.HasDesignatedRoom && Config.DesignatedRoom[RoomInfos.Count] != null) //执行指定了房间
  312. {
  313. roomSplit = Config.DesignatedRoom[RoomInfos.Count];
  314. }
  315. else //没有指定房间
  316. {
  317. //随机选择一个房间
  318. var list = RoomGroup.GetRoomList(roomType);
  319. if (list.Count == 0) //如果没有指定类型的房间, 或者房间数量不够, 就生成战斗房间
  320. {
  321. roomSplit = RoomGroup.GetRandomRoom(DungeonRoomType.Battle);
  322. }
  323. else
  324. {
  325. roomSplit = RoomGroup.GetRandomRoom(roomType);
  326. }
  327. }
  328. var room = new RoomInfo(_id, roomType, roomSplit);
  329.  
  330. //房间大小
  331. room.Size = new Vector2I((int)roomSplit.RoomInfo.Size.X, (int)roomSplit.RoomInfo.Size.Y);
  332.  
  333. if (prevRoom != null) //表示这不是第一个房间, 就得判断当前位置下的房间是否被遮挡
  334. {
  335. room.Layer = prevRoom.Layer + 1;
  336. if (_currMaxLayer < room.Layer)
  337. {
  338. _currMaxLayer = room.Layer;
  339. }
  340. //生成的位置可能会和上一个房间对不上, 需要多次尝试
  341. var tryCount = 0; //当前尝试次数
  342. var maxTryCount = _maxTryCount; //最大尝试次数
  343. if (roomType == DungeonRoomType.Outlet)
  344. {
  345. maxTryCount *= 3;
  346. }
  347. else if (roomType == DungeonRoomType.Boss)
  348. {
  349. maxTryCount *= 2;
  350. }
  351. for (; tryCount < maxTryCount; tryCount++)
  352. {
  353. //下一个房间方向
  354. var direction = _rule.GetNextRoomDoorDirection(prevRoom, roomType);
  355. //房间间隔
  356. var space = _rule.GetNextRoomInterval(prevRoom, roomType, direction);
  357. //中心偏移
  358. var offset = _rule.GetNextRoomOffset(prevRoom, roomType, direction);
  359.  
  360. //计算房间位置
  361. if (direction == RoomDirection.Up) //上
  362. {
  363. room.Position = new Vector2I(prevRoom.Position.X + offset,
  364. prevRoom.Position.Y - room.Size.Y - space);
  365. }
  366. else if (direction == RoomDirection.Right) //右
  367. {
  368. room.Position = new Vector2I(prevRoom.Position.X + prevRoom.Size.Y + space,
  369. prevRoom.Position.Y + offset);
  370. }
  371. else if (direction == RoomDirection.Down) //下
  372. {
  373. room.Position = new Vector2I(prevRoom.Position.X + offset,
  374. prevRoom.Position.Y + prevRoom.Size.Y + space);
  375. }
  376. else if (direction == RoomDirection.Left) //左
  377. {
  378. room.Position = new Vector2I(prevRoom.Position.X - room.Size.X - space,
  379. prevRoom.Position.Y + offset);
  380. }
  381.  
  382. //是否在限制区域内
  383. if (Config.EnableLimitRange)
  384. {
  385. if (room.GetHorizontalStart() < -_rangeX || room.GetHorizontalEnd() > _rangeX ||
  386. room.GetVerticalStart() < -_rangeY || room.GetVerticalEnd() > _rangeY)
  387. {
  388. //超出区域, 直接跳出尝试的循环, 返回 null
  389. resultRoomInfo = null;
  390. return GenerateRoomErrorCode.OutArea;
  391. }
  392. }
  393.  
  394. //是否碰到其他房间或者过道
  395. if (_roomGrid.RectCollision(room.Position - new Vector2I(2, 2), room.Size + new Vector2I(4, 5)))
  396. {
  397. //碰到其他墙壁, 再一次尝试
  398. continue;
  399. //return GenerateRoomErrorCode.HasCollision;
  400. }
  401. _roomGrid.SetRect(room.Position, room.Size, true);
  402.  
  403. //找门, 与上一个房间是否能连通
  404. if (!ConnectDoor(prevRoom, room))
  405. {
  406. _roomGrid.RemoveRect(room.Position, room.Size);
  407. //Debug.Log("链接通道失败");
  408. //房间过道没有连接上, 再一次尝试
  409. continue;
  410. //return GenerateRoomErrorCode.NoProperDoor;
  411. }
  412. break;
  413. }
  414.  
  415. //尝试次数用光了, 还没有找到合适的位置
  416. if (tryCount >= maxTryCount)
  417. {
  418. resultRoomInfo = null;
  419. return GenerateRoomErrorCode.NoSuitableLocation;
  420. }
  421. }
  422. else //第一个房间
  423. {
  424. room.Layer = 0;
  425. _roomGrid.SetRect(room.Position, room.Size, true);
  426. }
  427. _id++;
  428. room.Prev = prevRoom;
  429. if (prevRoom != null)
  430. {
  431. prevRoom.Next.Add(room);
  432. }
  433. resultRoomInfo = room;
  434. return GenerateRoomErrorCode.NoError;
  435. }
  436.  
  437. /// <summary>
  438. /// 设置上一个房间
  439. /// </summary>
  440. public void SetPrevRoom(RoomInfo roomInfo)
  441. {
  442. prevRoomInfo = roomInfo;
  443. }
  444.  
  445. /// <summary>
  446. /// 回滚一个房间
  447. /// </summary>
  448. public bool RollbackRoom(RoomInfo roomInfo)
  449. {
  450. if (roomInfo.Next.Count > 0)
  451. {
  452. Debug.LogError("当前房间还有连接的子房间, 不能回滚!");
  453. return false;
  454. }
  455.  
  456. if (!roomInfo.CanRollback)
  457. {
  458. Debug.LogError("当前房间不能回滚!");
  459. return false;
  460. }
  461. var prevRoom = roomInfo.Prev;
  462. //退掉占用的房间区域和过道占用区域
  463. _roomGrid.RemoveRect(roomInfo.Position, roomInfo.Size);
  464. foreach (var rect2 in roomInfo.AisleArea)
  465. {
  466. _roomGrid.RemoveRect(rect2.Position, rect2.Size);
  467. }
  468. //roomInfo.Doors[0].
  469. if (prevRoom != null)
  470. {
  471. roomInfo.Prev.Next.Remove(roomInfo);
  472. }
  473.  
  474. roomInfo.Prev = null;
  475. foreach (var roomInfoDoor in roomInfo.Doors)
  476. {
  477. var connectDoor = roomInfoDoor.ConnectDoor;
  478. connectDoor.RoomInfo.Doors.Remove(connectDoor);
  479. }
  480.  
  481. RoomInfos.Remove(roomInfo);
  482. switch (roomInfo.RoomType)
  483. {
  484. case DungeonRoomType.Battle:
  485. BattleRoomInfos.Remove(roomInfo);
  486. break;
  487. case DungeonRoomType.Inlet:
  488. StartRoomInfo = null;
  489. break;
  490. case DungeonRoomType.Outlet:
  491. EndRoomInfos.Remove(roomInfo);
  492. break;
  493. case DungeonRoomType.Boss:
  494. BossRoomInfos.Remove(roomInfo);
  495. break;
  496. case DungeonRoomType.Reward:
  497. RewardRoomInfos.Remove(roomInfo);
  498. break;
  499. case DungeonRoomType.Shop:
  500. ShopRoomInfos.Remove(roomInfo);
  501. break;
  502. case DungeonRoomType.Event:
  503. break;
  504. }
  505. roomInfo.Destroy();
  506. _id--;
  507. _nextRoomType = DungeonRoomType.None;
  508. SetPrevRoom(prevRoom);
  509. return true;
  510. }
  511.  
  512. /// <summary>
  513. /// 寻找层级最高的房间
  514. /// </summary>
  515. /// <param name="roomType">指定房间类型, 如果传 None 则表示选择所有类型房间</param>
  516. /// <param name="exclude">排除的房间</param>
  517. public RoomInfo FindMaxLayerRoom(DungeonRoomType roomType, List<RoomInfo> exclude = null)
  518. {
  519. RoomInfo temp = null;
  520. foreach (var roomInfo in RoomInfos)
  521. {
  522. if (roomInfo.CanRollback)
  523. {
  524. continue;
  525. }
  526. if ((temp == null || roomInfo.Layer > temp.Layer) && (roomType == DungeonRoomType.None || (roomInfo.RoomType & roomType) != DungeonRoomType.None) && (exclude == null || !exclude.Contains(roomInfo)))
  527. {
  528. temp = roomInfo;
  529. }
  530. }
  531.  
  532. return temp;
  533. }
  534.  
  535. /// <summary>
  536. /// 随机抽取层级小于 layer 的房间
  537. /// </summary>
  538. /// <param name="roomType">指定房间类型, 如果传 None 则表示选择所有类型房间</param>
  539. /// <param name="layer"></param>
  540. /// <param name="exclude">排除的房间</param>
  541. public RoomInfo RandomRoomLessThanLayer(DungeonRoomType roomType, int layer, List<RoomInfo> exclude = null)
  542. {
  543. _tempList.Clear();
  544. foreach (var roomInfo in RoomInfos)
  545. {
  546. if (roomInfo.CanRollback)
  547. {
  548. continue;
  549. }
  550. if (roomInfo.Layer < layer && (roomType == DungeonRoomType.None || (roomInfo.RoomType & roomType) != DungeonRoomType.None) && (exclude == null || !exclude.Contains(roomInfo)))
  551. {
  552. _tempList.Add(roomInfo);
  553. }
  554. }
  555.  
  556. return Random.RandomChoose(_tempList);
  557. }
  558. /// <summary>
  559. /// 随机抽取层级大于 layer 的房间
  560. /// </summary>
  561. /// <param name="roomType">指定房间类型, 如果传 None 则表示选择所有类型房间</param>
  562. /// <param name="layer"></param>
  563. /// <param name="exclude">排除的房间</param>
  564. public RoomInfo RandomRoomGreaterThanLayer(DungeonRoomType roomType, int layer, List<RoomInfo> exclude = null)
  565. {
  566. _tempList.Clear();
  567. foreach (var roomInfo in RoomInfos)
  568. {
  569. if (roomInfo.CanRollback)
  570. {
  571. continue;
  572. }
  573. if (roomInfo.Layer > layer && (roomType == DungeonRoomType.None || (roomInfo.RoomType & roomType) != DungeonRoomType.None) && (exclude == null || !exclude.Contains(roomInfo)))
  574. {
  575. _tempList.Add(roomInfo);
  576. }
  577. }
  578.  
  579. return Random.RandomChoose(_tempList);
  580. }
  581. /// <summary>
  582. /// 随机抽取房间
  583. /// </summary>
  584. /// <param name="roomType">指定房间类型, 如果传 None 则表示选择所有类型房间</param>
  585. public RoomInfo GetRandomRoom(DungeonRoomType roomType)
  586. {
  587. _tempList.Clear();
  588. foreach (var roomInfo in RoomInfos)
  589. {
  590. if (roomInfo.CanRollback)
  591. {
  592. continue;
  593. }
  594.  
  595. if (roomType == DungeonRoomType.None || (roomInfo.RoomType & roomType) != DungeonRoomType.None)
  596. {
  597. _tempList.Add(roomInfo);
  598. }
  599. }
  600.  
  601. return Random.RandomChoose(_tempList);
  602. }
  603.  
  604. /// <summary>
  605. /// 提交所有可以回滚的房间
  606. /// </summary>
  607. public void SubmitCanRollbackRoom()
  608. {
  609. foreach (var roomInfo in RoomInfos)
  610. {
  611. roomInfo.CanRollback = false;
  612. }
  613. }
  614. /// <summary>
  615. /// 找两个房间的门
  616. /// </summary>
  617. private bool ConnectDoor(RoomInfo roomInfo, RoomInfo nextRoomInfo)
  618. {
  619. //门描述
  620. var roomDoor = new RoomDoorInfo();
  621. var nextRoomDoor = new RoomDoorInfo();
  622. roomDoor.RoomInfo = roomInfo;
  623. roomDoor.IsForward = true;
  624. nextRoomDoor.RoomInfo = nextRoomInfo;
  625. roomDoor.ConnectRoom = nextRoomInfo;
  626. roomDoor.ConnectDoor = nextRoomDoor;
  627. nextRoomDoor.ConnectRoom = roomInfo;
  628. nextRoomDoor.ConnectDoor = roomDoor;
  629.  
  630. //先寻找直通门
  631. if (Random.RandomBoolean())
  632. {
  633. //直行通道, 优先纵轴
  634. if (TryConnectVerticalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor)
  635. || TryConnectHorizontalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor))
  636. {
  637. return true;
  638. }
  639. }
  640. else
  641. {
  642. //直行通道, 优先横轴
  643. if (TryConnectHorizontalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor)
  644. || TryConnectVerticalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor))
  645. {
  646. return true;
  647. }
  648. }
  649.  
  650. //包含1个拐角的通道
  651. return TryConnectCrossDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor);
  652. //包含2个拐角的通道 (后面再开发)
  653. }
  654.  
  655. /// <summary>
  656. /// 尝试寻找纵轴方向上两个房间的连通的门, 只查找直线通道, 返回是否找到
  657. /// </summary>
  658. private bool TryConnectVerticalDoor(RoomInfo roomInfo, RoomDoorInfo roomDoor, RoomInfo nextRoomInfo, RoomDoorInfo nextRoomDoor)
  659. {
  660. var overlapX = Mathf.Min(roomInfo.GetHorizontalEnd(), nextRoomInfo.GetHorizontalEnd()) -
  661. Mathf.Max(roomInfo.GetHorizontalStart(), nextRoomInfo.GetHorizontalStart());
  662. //这种情况下x轴有重叠
  663. if (overlapX >= 6)
  664. {
  665. //填充通通道地板格子
  666. var floorCell = new HashSet<Vector2I>();
  667. //找到重叠区域
  668. var rangeList = FindPassage(roomInfo, nextRoomInfo,
  669. roomInfo.GetVerticalStart() < nextRoomInfo.GetVerticalStart() ? DoorDirection.S : DoorDirection.N);
  670. while (rangeList.Count > 0)
  671. {
  672. //找到重叠区域
  673. var range = Random.RandomChooseAndRemove(rangeList);
  674. var x = Random.RandomRangeInt(range.X, range.Y) + 2;
  675. if (roomInfo.GetVerticalStart() < nextRoomInfo.GetVerticalStart()) //room在上, nextRoom在下
  676. {
  677. roomDoor.Direction = DoorDirection.S;
  678. nextRoomDoor.Direction = DoorDirection.N;
  679. roomDoor.OriginPosition = new Vector2I(x, roomInfo.GetVerticalDoorEnd());
  680. nextRoomDoor.OriginPosition = new Vector2I(x, nextRoomInfo.GetVerticalDoorStart());
  681.  
  682. var sv = roomInfo.GetVerticalDoorEnd() - 1;
  683. var ev = nextRoomInfo.GetVerticalDoorStart() + 1;
  684. for (var i = sv; i < ev; i++)
  685. {
  686. floorCell.Add(new Vector2I(x + 1, i));
  687. floorCell.Add(new Vector2I(x + 2, i));
  688. }
  689. }
  690. else //room在下, nextRoom在上
  691. {
  692. roomDoor.Direction = DoorDirection.N;
  693. nextRoomDoor.Direction = DoorDirection.S;
  694. roomDoor.OriginPosition = new Vector2I(x, roomInfo.GetVerticalDoorStart());
  695. nextRoomDoor.OriginPosition = new Vector2I(x, nextRoomInfo.GetVerticalDoorEnd());
  696.  
  697. var sv = nextRoomInfo.GetVerticalDoorEnd() - 1;
  698. var ev = roomInfo.GetVerticalDoorStart() + 1;
  699. for (var i = sv; i < ev; i++)
  700. {
  701. floorCell.Add(new Vector2I(x + 1, i));
  702. floorCell.Add(new Vector2I(x + 2, i));
  703. }
  704. }
  705.  
  706. //判断门之间的通道是否有物体碰到
  707. if (!AddCorridorToGridRange(roomDoor, nextRoomDoor))
  708. {
  709. //此门不能连通
  710. floorCell.Clear();
  711. continue;
  712. }
  713.  
  714. //没有撞到物体
  715. roomInfo.Doors.Add(roomDoor);
  716. nextRoomInfo.Doors.Add(nextRoomDoor);
  717.  
  718. roomDoor.AisleFloorCell = floorCell;
  719. nextRoomDoor.AisleFloorCell = floorCell;
  720. roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);;
  721. nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
  722. return true;
  723. }
  724. }
  725. return false;
  726. }
  727.  
  728. /// <summary>
  729. /// 尝试寻找横轴方向上两个房间的连通的门, 只查找直线通道, 返回是否找到
  730. /// </summary>
  731. private bool TryConnectHorizontalDoor(RoomInfo roomInfo, RoomDoorInfo roomDoor, RoomInfo nextRoomInfo, RoomDoorInfo nextRoomDoor)
  732. {
  733. var overlapY = Mathf.Min(roomInfo.GetVerticalEnd(), nextRoomInfo.GetVerticalEnd()) -
  734. Mathf.Max(roomInfo.GetVerticalStart(), nextRoomInfo.GetVerticalStart());
  735. //这种情况下y轴有重叠
  736. if (overlapY >= 6)
  737. {
  738. //填充通通道地板格子
  739. var floorCell = new HashSet<Vector2I>();
  740. //找到重叠区域
  741. var rangeList = FindPassage(roomInfo, nextRoomInfo,
  742. roomInfo.GetHorizontalStart() < nextRoomInfo.GetHorizontalStart() ? DoorDirection.E : DoorDirection.W);
  743.  
  744. while (rangeList.Count > 0)
  745. {
  746. //找到重叠区域
  747. var range = Random.RandomChooseAndRemove(rangeList);
  748. var y = Random.RandomRangeInt(range.X, range.Y) + 3;
  749. if (roomInfo.GetHorizontalStart() < nextRoomInfo.GetHorizontalStart()) //room在左, nextRoom在右
  750. {
  751. roomDoor.Direction = DoorDirection.E;
  752. nextRoomDoor.Direction = DoorDirection.W;
  753. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorEnd(), y);
  754. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart(), y);
  755.  
  756. var sv = roomInfo.GetHorizontalDoorEnd() - 1;
  757. var ev = nextRoomInfo.GetHorizontalDoorStart() + 1;
  758. for (var i = sv; i < ev; i++)
  759. {
  760. floorCell.Add(new Vector2I(i, y + 2));
  761. }
  762. }
  763. else //room在右, nextRoom在左
  764. {
  765. roomDoor.Direction = DoorDirection.W;
  766. nextRoomDoor.Direction = DoorDirection.E;
  767. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart(), y);
  768. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorEnd(), y);
  769.  
  770. var sv = nextRoomInfo.GetHorizontalDoorEnd() - 1;
  771. var ev = roomInfo.GetHorizontalDoorStart() + 1;
  772. for (var i = sv; i < ev; i++)
  773. {
  774. floorCell.Add(new Vector2I(i, y + 2));
  775. }
  776. }
  777.  
  778. //判断门之间的通道是否有物体碰到
  779. if (!AddCorridorToGridRange(roomDoor, nextRoomDoor))
  780. {
  781. //此门不能连通
  782. floorCell.Clear();
  783. continue;
  784. }
  785.  
  786. //没有撞到物体
  787. roomInfo.Doors.Add(roomDoor);
  788. nextRoomInfo.Doors.Add(nextRoomDoor);
  789. roomDoor.AisleFloorCell = floorCell;
  790. nextRoomDoor.AisleFloorCell = floorCell;
  791. roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);;
  792. nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
  793. return true;
  794. }
  795. }
  796.  
  797. return false;
  798. }
  799.  
  800. /// <summary>
  801. /// 尝试寻找包含拐角的两个房间的连通的门, 返回是否找到
  802. /// </summary>
  803. private bool TryConnectCrossDoor(RoomInfo roomInfo, RoomDoorInfo roomDoor, RoomInfo nextRoomInfo, RoomDoorInfo nextRoomDoor)
  804. {
  805. //焦点
  806. Vector2I cross = default;
  807.  
  808. if (roomInfo.GetHorizontalStart() > nextRoomInfo.GetHorizontalStart())
  809. {
  810. if (roomInfo.GetVerticalStart() > nextRoomInfo.GetVerticalStart())
  811. {
  812. if (Random.RandomBoolean()) //↑ //→
  813. {
  814. if (!TryConnect_NE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  815. !TryConnect_WS_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  816. {
  817. return false;
  818. }
  819. }
  820. else //← //↓
  821. {
  822. if (!TryConnect_WS_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  823. !TryConnect_NE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  824. {
  825. return false;
  826. }
  827. }
  828. }
  829. else
  830. {
  831. if (Random.RandomBoolean()) //↓ //→
  832. {
  833. if (!TryConnect_SE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  834. !TryConnect_WN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  835. {
  836. return false;
  837. }
  838. }
  839. else //← //↑
  840. {
  841. if (!TryConnect_WN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  842. !TryConnect_SE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  843. {
  844. return false;
  845. }
  846. }
  847. }
  848. }
  849. else
  850. {
  851. if (roomInfo.GetVerticalStart() > nextRoomInfo.GetVerticalStart()) //→ //↓
  852. {
  853. if (Random.RandomBoolean())
  854. {
  855. if (!TryConnect_ES_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  856. !TryConnect_NW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  857. {
  858. return false;
  859. }
  860. }
  861. else //↑ //←
  862. {
  863. if (!TryConnect_NW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  864. !TryConnect_ES_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  865. {
  866. return false;
  867. }
  868. }
  869. }
  870. else
  871. {
  872. if (Random.RandomBoolean()) //→ //↑
  873. {
  874. if (!TryConnect_EN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  875. !TryConnect_SW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  876. {
  877. return false;
  878. }
  879. }
  880. else //↓ //←
  881. {
  882. if (!TryConnect_SW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  883. !TryConnect_EN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  884. {
  885. return false;
  886. }
  887. }
  888. }
  889. }
  890.  
  891. //判断门之间的通道是否有物体碰到
  892. if (!AddCorridorToGridRange(roomDoor, nextRoomDoor, cross))
  893. {
  894. //此门不能连通
  895. return false;
  896. }
  897.  
  898. roomDoor.HasCross = true;
  899. roomDoor.Cross = cross;
  900. nextRoomDoor.HasCross = true;
  901. nextRoomDoor.Cross = cross;
  902.  
  903. roomInfo.Doors.Add(roomDoor);
  904. nextRoomInfo.Doors.Add(nextRoomDoor);
  905. return true;
  906. }
  907.  
  908. private bool FindCrossPassage(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor,ref int offset1, ref int offset2)
  909. {
  910. var room1 = roomInfo.RoomSplit.RoomInfo;
  911. var room2 = nextRoomInfo.RoomSplit.RoomInfo;
  912. int? temp1 = null;
  913. int? temp2 = null;
  914.  
  915. foreach (var areaInfo1 in room1.GetCompletionDoorArea())
  916. {
  917. if (areaInfo1.Direction == roomDoor.Direction)
  918. {
  919. FindCrossPassage_Area(areaInfo1, roomInfo, nextRoomInfo, ref temp1);
  920. }
  921. }
  922. if (temp1 == null)
  923. {
  924. return false;
  925. }
  926.  
  927. foreach (var areaInfo2 in room2.GetCompletionDoorArea())
  928. {
  929. if (areaInfo2.Direction == nextRoomDoor.Direction)
  930. {
  931. FindCrossPassage_Area(areaInfo2, nextRoomInfo, roomInfo, ref temp2);
  932. }
  933. }
  934.  
  935. if (temp2 == null)
  936. {
  937. return false;
  938. }
  939. offset1 = temp1.Value;
  940. offset2 = temp2.Value;
  941. return true;
  942. }
  943.  
  944. private void FindCrossPassage_Area(DoorAreaInfo areaInfo, RoomInfo room1, RoomInfo room2, ref int? areaRange)
  945. {
  946. if (areaInfo.Direction == DoorDirection.N || areaInfo.Direction == DoorDirection.S) //纵向门
  947. {
  948. var num = room1.GetHorizontalStart();
  949. var p1 = num + GetDoorAreaInfoStart(areaInfo) / GameConfig.TileCellSize;
  950. var p2 = num + GetDoorAreaInfoEnd(areaInfo) / GameConfig.TileCellSize;
  951.  
  952. if (room1.Position.X > room2.Position.X)
  953. {
  954. var range = CalcOverlapRange(room2.GetHorizontalEnd() + GameConfig.RoomSpace,
  955. room1.GetHorizontalEnd(), p1, p2);
  956. //交集范围够生成门
  957. if (range.Y - range.X >= GameConfig.CorridorWidth)
  958. {
  959. // var tempRange = new Vector2I(Mathf.Abs(room1.Position.X - (int)range.X),
  960. // Mathf.Abs(room1.Position.X - (int)range.Y) - GameConfig.CorridorWidth);
  961. var rangeValue = Mathf.Abs(room1.Position.X - (int)range.X);
  962.  
  963. if (areaRange == null || rangeValue < areaRange)
  964. {
  965. areaRange = rangeValue;
  966. }
  967. }
  968. }
  969. else
  970. {
  971. var range = CalcOverlapRange(room1.GetHorizontalStart(),
  972. room2.GetHorizontalStart() - + GameConfig.RoomSpace, p1, p2);
  973. //交集范围够生成门
  974. if (range.Y - range.X >= GameConfig.CorridorWidth)
  975. {
  976. // var tempRange = new Vector2I(Mathf.Abs(room1.Position.X - (int)range.X),
  977. // Mathf.Abs(room1.Position.X - (int)range.Y) - GameConfig.CorridorWidth);
  978.  
  979. var rangeValue = Mathf.Abs(room1.Position.X - (int)range.Y) - GameConfig.CorridorWidth;
  980.  
  981. if (areaRange == null || rangeValue > areaRange)
  982. {
  983. areaRange = rangeValue;
  984. }
  985. }
  986. }
  987. }
  988. else //横向门
  989. {
  990. var num = room1.GetVerticalStart();
  991. var p1 = num + GetDoorAreaInfoStart(areaInfo) / GameConfig.TileCellSize;
  992. var p2 = num + GetDoorAreaInfoEnd(areaInfo) / GameConfig.TileCellSize;
  993.  
  994. if (room1.Position.Y > room2.Position.Y)
  995. {
  996. var range = CalcOverlapRange(room2.GetVerticalEnd() + GameConfig.RoomSpace,
  997. room1.GetVerticalEnd(), p1, p2);
  998. //交集范围够生成门
  999. if (range.Y - range.X >= GameConfig.CorridorWidth)
  1000. {
  1001. // var tempRange = new Vector2I(Mathf.Abs(room1.Position.Y - (int)range.X),
  1002. // Mathf.Abs(room1.Position.Y - (int)range.Y) - GameConfig.CorridorWidth);
  1003.  
  1004. var rangeValue = Mathf.Abs(room1.Position.Y - (int)range.X);
  1005.  
  1006. if (areaRange == null || rangeValue < areaRange)
  1007. {
  1008. areaRange = rangeValue;
  1009. }
  1010. }
  1011. }
  1012. else
  1013. {
  1014. var range = CalcOverlapRange(room1.GetVerticalStart(),
  1015. room2.GetVerticalStart() - GameConfig.RoomSpace, p1, p2);
  1016. //交集范围够生成门
  1017. if (range.Y - range.X >= GameConfig.CorridorWidth)
  1018. {
  1019. // var tempRange = new Vector2I(Mathf.Abs(room1.Position.Y - (int)range.X),
  1020. // Mathf.Abs(room1.Position.Y - (int)range.Y) - GameConfig.CorridorWidth);
  1021. var rangeValue = Mathf.Abs(room1.Position.Y - (int)range.Y) - GameConfig.CorridorWidth;
  1022.  
  1023. if (areaRange == null || rangeValue > areaRange)
  1024. {
  1025. areaRange = rangeValue;
  1026. }
  1027. }
  1028. }
  1029. }
  1030. }
  1031.  
  1032. private bool TryConnect_NE_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1033. {
  1034. var offset1 = 0;
  1035. var offset2 = 0;
  1036. roomDoor.Direction = DoorDirection.N; //↑
  1037. nextRoomDoor.Direction = DoorDirection.E; //→
  1038.  
  1039. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1040. {
  1041. return false;
  1042. }
  1043.  
  1044. offset1 += 1;
  1045. offset2 += 1;
  1046. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart() + offset1, roomInfo.GetVerticalDoorStart());
  1047. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorEnd(), nextRoomInfo.GetVerticalDoorStart() + offset2);
  1048. cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  1049.  
  1050. var floorCell = new HashSet<Vector2I>();
  1051.  
  1052. //纵轴地板
  1053. for (var y = cross.Y + 3; y <= roomDoor.OriginPosition.Y; y++)
  1054. {
  1055. floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 1, y));
  1056. floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 2, y));
  1057. }
  1058. //横轴地板
  1059. for (var x = nextRoomDoor.OriginPosition.X - 1; x <= cross.X; x++)
  1060. {
  1061. floorCell.Add(new Vector2I(x, nextRoomDoor.OriginPosition.Y + 2));
  1062. }
  1063. //交叉点地板
  1064. floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
  1065. floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
  1066. roomDoor.AisleFloorCell = floorCell;
  1067. nextRoomDoor.AisleFloorCell = floorCell;
  1068. roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
  1069. nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
  1070. return true;
  1071. }
  1072.  
  1073. private bool TryConnect_WS_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1074. {
  1075. var offset1 = 0;
  1076. var offset2 = 0;
  1077. roomDoor.Direction = DoorDirection.W; //←
  1078. nextRoomDoor.Direction = DoorDirection.S; //↓
  1079. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1080. {
  1081. return false;
  1082. }
  1083.  
  1084. offset1 += 1;
  1085. offset2 += 1;
  1086. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart(), roomInfo.GetVerticalDoorStart() + offset1);
  1087. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart() + offset2, nextRoomInfo.GetVerticalDoorEnd());
  1088. cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  1089. var floorCell = new HashSet<Vector2I>();
  1090.  
  1091. //横轴地板
  1092. for (var x = cross.X + 3; x <= roomDoor.OriginPosition.X; x++)
  1093. {
  1094. floorCell.Add(new Vector2I(x, roomDoor.OriginPosition.Y + 2));
  1095. }
  1096. //纵轴地板
  1097. for (var y = nextRoomDoor.OriginPosition.Y - 1; y <= cross.Y + 1; y++)
  1098. {
  1099. floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 1, y));
  1100. floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 2, y));
  1101. }
  1102.  
  1103. //交叉点地板
  1104. floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
  1105. floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
  1106. roomDoor.AisleFloorCell = floorCell;
  1107. nextRoomDoor.AisleFloorCell = floorCell;
  1108. roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
  1109. nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
  1110. return true;
  1111. }
  1112.  
  1113. private bool TryConnect_SE_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1114. {
  1115. var offset1 = 0;
  1116. var offset2 = 0;
  1117. roomDoor.Direction = DoorDirection.S; //↓
  1118. nextRoomDoor.Direction = DoorDirection.E; //→
  1119. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1120. {
  1121. return false;
  1122. }
  1123.  
  1124. offset1 += 1;
  1125. offset2 += 1;
  1126. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart() + offset1, roomInfo.GetVerticalDoorEnd());
  1127. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorEnd(), nextRoomInfo.GetVerticalDoorStart() + offset2);
  1128. cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  1129. var floorCell = new HashSet<Vector2I>();
  1130. //纵轴地板
  1131. for (var y = roomDoor.OriginPosition.Y - 1; y <= cross.Y + 1; y++)
  1132. {
  1133. floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 1, y));
  1134. floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 2, y));
  1135. }
  1136. //横轴地板
  1137. for (var x = nextRoomDoor.OriginPosition.X - 1; x <= cross.X; x++)
  1138. {
  1139. floorCell.Add(new Vector2I(x, nextRoomDoor.OriginPosition.Y + 2));
  1140. }
  1141. //交叉点地板
  1142. floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
  1143. floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
  1144. roomDoor.AisleFloorCell = floorCell;
  1145. nextRoomDoor.AisleFloorCell = floorCell;
  1146. roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
  1147. nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
  1148. return true;
  1149. }
  1150.  
  1151. private bool TryConnect_WN_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1152. {
  1153. var offset1 = 0;
  1154. var offset2 = 0;
  1155. roomDoor.Direction = DoorDirection.W; //←
  1156. nextRoomDoor.Direction = DoorDirection.N; //↑
  1157. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1158. {
  1159. return false;
  1160. }
  1161.  
  1162. offset1 += 1;
  1163. offset2 += 1;
  1164. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart(), roomInfo.GetVerticalDoorStart() + offset1); //
  1165. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart() + offset2, nextRoomInfo.GetVerticalDoorStart());
  1166. cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  1167. var floorCell = new HashSet<Vector2I>();
  1168. //横轴地板
  1169. for (var x = cross.X + 3; x <= roomDoor.OriginPosition.X; x++)
  1170. {
  1171. floorCell.Add(new Vector2I(x, roomDoor.OriginPosition.Y + 2));
  1172. }
  1173. //纵轴地板
  1174. for (var y = cross.Y + 3; y <= nextRoomDoor.OriginPosition.Y; y++)
  1175. {
  1176. floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 1, y));
  1177. floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 2, y));
  1178. }
  1179. //交叉点地板
  1180. floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
  1181. floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
  1182. roomDoor.AisleFloorCell = floorCell;
  1183. nextRoomDoor.AisleFloorCell = floorCell;
  1184. roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
  1185. nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
  1186. return true;
  1187. }
  1188. private bool TryConnect_ES_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1189. {
  1190. var offset1 = 0;
  1191. var offset2 = 0;
  1192. roomDoor.Direction = DoorDirection.E; //→
  1193. nextRoomDoor.Direction = DoorDirection.S; //↓
  1194.  
  1195. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1196. {
  1197. return false;
  1198. }
  1199.  
  1200. offset1 += 1;
  1201. offset2 += 1;
  1202. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorEnd(), roomInfo.GetVerticalDoorStart() + offset1);
  1203. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart() + offset2, nextRoomInfo.GetVerticalDoorEnd());
  1204. cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  1205. var floorCell = new HashSet<Vector2I>();
  1206. //横轴地板
  1207. for (var x = roomDoor.OriginPosition.X - 1; x <= cross.X; x++)
  1208. {
  1209. floorCell.Add(new Vector2I(x, roomDoor.OriginPosition.Y + 2));
  1210. }
  1211. //纵轴地板
  1212. for (var y = nextRoomDoor.OriginPosition.Y - 1; y <= cross.Y + 1; y++)
  1213. {
  1214. floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 1, y));
  1215. floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 2, y));
  1216. }
  1217. //交叉点地板
  1218. floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
  1219. floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
  1220. roomDoor.AisleFloorCell = floorCell;
  1221. nextRoomDoor.AisleFloorCell = floorCell;
  1222. roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
  1223. nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
  1224. return true;
  1225. }
  1226. private bool TryConnect_NW_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1227. {
  1228. var offset1 = 0;
  1229. var offset2 = 0;
  1230. roomDoor.Direction = DoorDirection.N; //↑
  1231. nextRoomDoor.Direction = DoorDirection.W; //←
  1232.  
  1233. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1234. {
  1235. return false;
  1236. }
  1237.  
  1238. offset1 += 1;
  1239. offset2 += 1;
  1240. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart() + offset1, roomInfo.GetVerticalDoorStart());
  1241. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart(), nextRoomInfo.GetVerticalDoorStart() + offset2);
  1242. cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  1243. var floorCell = new HashSet<Vector2I>();
  1244. //纵轴地板
  1245. for (var y = cross.Y + 3; y <= roomDoor.OriginPosition.Y; y++)
  1246. {
  1247. floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 1, y));
  1248. floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 2, y));
  1249. }
  1250. //横轴地板
  1251. for (var x = cross.X + 3; x <= nextRoomDoor.OriginPosition.X; x++)
  1252. {
  1253. floorCell.Add(new Vector2I(x, nextRoomDoor.OriginPosition.Y + 2));
  1254. }
  1255. //交叉点地板
  1256. floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
  1257. floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
  1258. roomDoor.AisleFloorCell = floorCell;
  1259. nextRoomDoor.AisleFloorCell = floorCell;
  1260. roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
  1261. nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
  1262. return true;
  1263. }
  1264. private bool TryConnect_EN_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1265. {
  1266. var offset1 = 0;
  1267. var offset2 = 0;
  1268. roomDoor.Direction = DoorDirection.E; //→
  1269. nextRoomDoor.Direction = DoorDirection.N; //↑
  1270.  
  1271. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1272. {
  1273. return false;
  1274. }
  1275. offset1 += 1;
  1276. offset2 += 2;
  1277. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorEnd(), roomInfo.GetVerticalDoorStart() + offset1);
  1278. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalStart() + offset2, nextRoomInfo.GetVerticalDoorStart());
  1279. cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  1280. var floorCell = new HashSet<Vector2I>();
  1281. //横轴地板
  1282. for (var x = roomDoor.OriginPosition.X - 1; x <= cross.X; x++)
  1283. {
  1284. floorCell.Add(new Vector2I(x, roomDoor.OriginPosition.Y + 2));
  1285. }
  1286. //纵轴地板
  1287. for (var y = cross.Y + 3; y <= nextRoomDoor.OriginPosition.Y; y++)
  1288. {
  1289. floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 1, y));
  1290. floorCell.Add(new Vector2I(nextRoomDoor.OriginPosition.X + 2, y));
  1291. }
  1292. //交叉点地板
  1293. floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
  1294. floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
  1295. roomDoor.AisleFloorCell = floorCell;
  1296. nextRoomDoor.AisleFloorCell = floorCell;
  1297. roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
  1298. nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
  1299. return true;
  1300. }
  1301.  
  1302. private bool TryConnect_SW_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1303. {
  1304. var offset1 = 0;
  1305. var offset2 = 0;
  1306. roomDoor.Direction = DoorDirection.S; //↓
  1307. nextRoomDoor.Direction = DoorDirection.W; //←
  1308.  
  1309. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1310. {
  1311. return false;
  1312. }
  1313.  
  1314. offset1 += 1;
  1315. offset2 += 1;
  1316. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart() + offset1, roomInfo.GetVerticalDoorEnd());
  1317. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart(), nextRoomInfo.GetVerticalDoorStart() + offset2);
  1318. cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  1319. var floorCell = new HashSet<Vector2I>();
  1320. //纵轴地板
  1321. for (var y = roomDoor.OriginPosition.Y - 1; y <= cross.Y + 1; y++)
  1322. {
  1323. floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 1, y));
  1324. floorCell.Add(new Vector2I(roomDoor.OriginPosition.X + 2, y));
  1325. }
  1326. //横轴地板
  1327. for (var x = cross.X + 3; x <= nextRoomDoor.OriginPosition.X; x++)
  1328. {
  1329. floorCell.Add(new Vector2I(x, nextRoomDoor.OriginPosition.Y + 2));
  1330. }
  1331. //交叉点地板
  1332. floorCell.Add(new Vector2I(cross.X + 1, cross.Y + 2));
  1333. floorCell.Add(new Vector2I(cross.X + 2, cross.Y + 2));
  1334. roomDoor.AisleFloorCell = floorCell;
  1335. nextRoomDoor.AisleFloorCell = floorCell;
  1336. roomDoor.AisleFloorRect = Utils.CalcRect(floorCell);
  1337. nextRoomDoor.AisleFloorRect = roomDoor.AisleFloorRect;
  1338. return true;
  1339. }
  1340.  
  1341. /// <summary>
  1342. /// 查找房间的连接通道, 函数返回是否找到对应的门, 通过 result 返回 x/y 轴坐标
  1343. /// </summary>
  1344. /// <param name="roomInfo">第一个房间</param>
  1345. /// <param name="nextRoomInfo">第二个房间</param>
  1346. /// <param name="direction">第一个房间连接方向</param>
  1347. private List<Vector2I> FindPassage(RoomInfo roomInfo, RoomInfo nextRoomInfo, DoorDirection direction)
  1348. {
  1349. var room1 = roomInfo.RoomSplit.RoomInfo;
  1350. var room2 = nextRoomInfo.RoomSplit.RoomInfo;
  1351. //用于存储符合生成条件的区域
  1352. var rangeList = new List<Vector2I>();
  1353. foreach (var doorAreaInfo1 in room1.GetCompletionDoorArea())
  1354. {
  1355. if (doorAreaInfo1.Direction == direction)
  1356. {
  1357. //第二个门的方向
  1358. var direction2 = GetReverseDirection(direction);
  1359. foreach (var doorAreaInfo2 in room2.GetCompletionDoorArea())
  1360. {
  1361. if (doorAreaInfo2.Direction == direction2)
  1362. {
  1363. Vector2 range;
  1364. if (direction == DoorDirection.E || direction == DoorDirection.W) //第二个门向← 或者 第二个门向→
  1365. {
  1366. range = CalcOverlapRange(
  1367. roomInfo.GetVerticalStart() * GameConfig.TileCellSize + GetDoorAreaInfoStart(doorAreaInfo1), roomInfo.GetVerticalStart() * GameConfig.TileCellSize + GetDoorAreaInfoEnd(doorAreaInfo1),
  1368. nextRoomInfo.GetVerticalStart() * GameConfig.TileCellSize + GetDoorAreaInfoStart(doorAreaInfo2), nextRoomInfo.GetVerticalStart() * GameConfig.TileCellSize + GetDoorAreaInfoEnd(doorAreaInfo2)
  1369. );
  1370. }
  1371. else //第二个门向↑ 或者 第二个门向↓
  1372. {
  1373. range = CalcOverlapRange(
  1374. roomInfo.GetHorizontalStart() * GameConfig.TileCellSize + GetDoorAreaInfoStart(doorAreaInfo1), roomInfo.GetHorizontalStart() * GameConfig.TileCellSize + GetDoorAreaInfoEnd(doorAreaInfo1),
  1375. nextRoomInfo.GetHorizontalStart() * GameConfig.TileCellSize + GetDoorAreaInfoStart(doorAreaInfo2), nextRoomInfo.GetHorizontalStart() * GameConfig.TileCellSize + GetDoorAreaInfoEnd(doorAreaInfo2)
  1376. );
  1377. }
  1378. //交集范围够生成门
  1379. if (range.Y - range.X >= GameConfig.CorridorWidth * GameConfig.TileCellSize)
  1380. {
  1381. rangeList.Add(new Vector2I((int)(range.X / GameConfig.TileCellSize), (int)(range.Y / GameConfig.TileCellSize) - GameConfig.CorridorWidth));
  1382. }
  1383. }
  1384. }
  1385. }
  1386. }
  1387. return rangeList;
  1388. }
  1389. /// <summary>
  1390. /// 用于计算重叠区域坐标, 可以理解为一维轴上4个点的中间两个点, 返回的x为起始点, y为结束点
  1391. /// </summary>
  1392. private Vector2 CalcOverlapRange(float start1, float end1, float start2, float end2)
  1393. {
  1394. return new Vector2(Mathf.Max(start1, start2), Mathf.Min(end1, end2));
  1395. }
  1396.  
  1397. /// <summary>
  1398. /// 返回 p1 - p2 是否在 start - end 范围内
  1399. /// </summary>
  1400. private bool IsInRange(float start, float end, float p1, float p2)
  1401. {
  1402. return p1 >= start && p2 <= end;
  1403. }
  1404. //返回指定方向的反方向
  1405. //0上, 1右, 2下, 3左
  1406. private int GetReverseDirection(int direction)
  1407. {
  1408. switch (direction)
  1409. {
  1410. case 0: return 2;
  1411. case 1: return 3;
  1412. case 2: return 0;
  1413. case 3: return 1;
  1414. }
  1415.  
  1416. return 2;
  1417. }
  1418. //返回参数方向的反方向
  1419. private DoorDirection GetReverseDirection(DoorDirection direction)
  1420. {
  1421. switch (direction)
  1422. {
  1423. case DoorDirection.E:
  1424. return DoorDirection.W;
  1425. case DoorDirection.W:
  1426. return DoorDirection.E;
  1427. case DoorDirection.S:
  1428. return DoorDirection.N;
  1429. case DoorDirection.N:
  1430. return DoorDirection.S;
  1431. }
  1432.  
  1433. return DoorDirection.S;
  1434. }
  1435.  
  1436. //将两个门间的过道占用数据存入RoomGrid
  1437. private bool AddCorridorToGridRange(RoomDoorInfo door1, RoomDoorInfo door2)
  1438. {
  1439. var point1 = door1.OriginPosition;
  1440. var point2 = door2.OriginPosition;
  1441. var pos = new Vector2I(Mathf.Min(point1.X, point2.X), Mathf.Min(point1.Y, point2.Y));
  1442. var size = new Vector2I(
  1443. point1.X == point2.X ? GameConfig.CorridorWidth : Mathf.Abs(point1.X - point2.X),
  1444. point1.Y == point2.Y ? GameConfig.CorridorWidth : Mathf.Abs(point1.Y - point2.Y)
  1445. );
  1446.  
  1447. Vector2I collPos;
  1448. Vector2I collSize;
  1449. if (point1.X == point2.X) //纵向加宽, 防止贴到其它墙
  1450. {
  1451. pos.Y += 1;
  1452. size.Y -= 3;
  1453. collPos = new Vector2I(pos.X - GameConfig.RoomSpace, pos.Y);
  1454. collSize = new Vector2I(size.X + GameConfig.RoomSpace * 2, size.Y);
  1455. }
  1456. else //横向加宽, 防止贴到其它墙
  1457. {
  1458. pos.X += 1;
  1459. size.X -= 2;
  1460. collPos = new Vector2I(pos.X, pos.Y - GameConfig.RoomSpace);
  1461. collSize = new Vector2I(size.X, size.Y + GameConfig.RoomSpace * 2);
  1462. }
  1463.  
  1464. if (_roomGrid.RectCollision(collPos, collSize))
  1465. {
  1466. return false;
  1467. }
  1468.  
  1469. door2.RoomInfo.AisleArea.Add(new Rect2I(pos, size));
  1470. _roomGrid.SetRect(pos, size, true);
  1471. return true;
  1472. }
  1473.  
  1474. //将两个门间的过道占用数据存入RoomGrid, 该重载加入拐角点
  1475. private bool AddCorridorToGridRange(RoomDoorInfo door1, RoomDoorInfo door2, Vector2I cross)
  1476. {
  1477. if (_roomGrid.RectCollision(cross - new Vector2I(1, 2), new Vector2I(GameConfig.CorridorWidth + 2, GameConfig.CorridorWidth + 3)))
  1478. {
  1479. return false;
  1480. }
  1481. var point1 = door1.OriginPosition;
  1482. var point2 = door2.OriginPosition;
  1483. var pos1 = new Vector2I(Mathf.Min(point1.X, cross.X), Mathf.Min(point1.Y, cross.Y));
  1484. var size1 = new Vector2I(
  1485. point1.X == cross.X ? GameConfig.CorridorWidth : Mathf.Abs(point1.X - cross.X),
  1486. point1.Y == cross.Y ? GameConfig.CorridorWidth : Mathf.Abs(point1.Y - cross.Y)
  1487. );
  1488. var pos2 = new Vector2I(Mathf.Min(point2.X, cross.X), Mathf.Min(point2.Y, cross.Y));
  1489. var size2 = new Vector2I(
  1490. point2.X == cross.X ? GameConfig.CorridorWidth : Mathf.Abs(point2.X - cross.X),
  1491. point2.Y == cross.Y ? GameConfig.CorridorWidth : Mathf.Abs(point2.Y - cross.Y)
  1492. );
  1493.  
  1494. Vector2I collPos1;
  1495. Vector2I collSize1;
  1496. if (point1.X == cross.X) //纵向加宽, 防止贴到其它墙
  1497. {
  1498. if (door1.Direction == DoorDirection.N)
  1499. {
  1500. size1.Y -= 2;
  1501. }
  1502. else
  1503. {
  1504. pos1.Y += 1;
  1505. size1.Y -= 1;
  1506. }
  1507. collPos1 = new Vector2I(pos1.X - GameConfig.RoomSpace, pos1.Y);
  1508. collSize1 = new Vector2I(size1.X + GameConfig.RoomSpace * 2, size1.Y);
  1509. }
  1510. else //横向加宽, 防止贴到其它墙
  1511. {
  1512. if (door1.Direction == DoorDirection.E)
  1513. {
  1514. pos1.X += 1;
  1515. size1.X -= 1;
  1516. }
  1517. else
  1518. {
  1519. size1.X -= 1;
  1520. }
  1521. collPos1 = new Vector2I(pos1.X, pos1.Y - GameConfig.RoomSpace);
  1522. collSize1 = new Vector2I(size1.X, size1.Y + GameConfig.RoomSpace * 2);
  1523. }
  1524.  
  1525. if (_roomGrid.RectCollision(collPos1, collSize1))
  1526. {
  1527. return false;
  1528. }
  1529.  
  1530. Vector2I collPos2;
  1531. Vector2I collSize2;
  1532. if (point2.X == cross.X) //纵向加宽, 防止贴到其它墙
  1533. {
  1534. if (door2.Direction == DoorDirection.N)
  1535. {
  1536. size2.Y -= 2;
  1537. }
  1538. else
  1539. {
  1540. pos2.Y += 1;
  1541. size2.Y -= 1;
  1542. }
  1543. collPos2 = new Vector2I(pos2.X - GameConfig.RoomSpace, pos2.Y);
  1544. collSize2 = new Vector2I(size2.X + GameConfig.RoomSpace * 2, size2.Y);
  1545. }
  1546. else //横向加宽, 防止贴到其它墙
  1547. {
  1548. if (door2.Direction == DoorDirection.E)
  1549. {
  1550. pos2.X += 1;
  1551. size2.X -= 1;
  1552. }
  1553. else
  1554. {
  1555. size2.X -= 1;
  1556. }
  1557. collPos2 = new Vector2I(pos2.X, pos2.Y - GameConfig.RoomSpace);
  1558. collSize2 = new Vector2I(size2.X, size2.Y + GameConfig.RoomSpace * 2);
  1559. }
  1560.  
  1561. if (_roomGrid.RectCollision(collPos2, collSize2))
  1562. {
  1563. return false;
  1564. }
  1565.  
  1566. door2.RoomInfo.AisleArea.Add(new Rect2I(pos1, size1));
  1567. door2.RoomInfo.AisleArea.Add(new Rect2I(pos2, size2));
  1568. _roomGrid.SetRect(pos1, size1, true);
  1569. _roomGrid.SetRect(pos2, size2, true);
  1570. return true;
  1571. }
  1572.  
  1573. private int GetDoorAreaInfoStart(DoorAreaInfo areaInfo)
  1574. {
  1575. return areaInfo.Start;
  1576. }
  1577.  
  1578. private int GetDoorAreaInfoEnd(DoorAreaInfo areaInfo)
  1579. {
  1580. return areaInfo.End;
  1581. }
  1582. }