Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / DungeonGenerator.cs
  1.  
  2. using System;
  3. using System.Collections.Generic;
  4. using Godot;
  5.  
  6. /// <summary>
  7. /// 地牢生成器
  8. /// </summary>
  9. public class DungeonGenerator
  10. {
  11. /// <summary>
  12. /// 所有生成的房间, 调用过 Generate() 函数才能获取到值
  13. /// </summary>
  14. public List<RoomInfo> RoomInfos { get; } = new List<RoomInfo>();
  15.  
  16. /// <summary>
  17. /// 起始房间
  18. /// </summary>
  19. public RoomInfo StartRoomInfo { get; private set; }
  20. /// <summary>
  21. /// 结束房间
  22. /// </summary>
  23. public RoomInfo EndRoomInfo { get; private set; }
  24.  
  25. /// <summary>
  26. /// boss房间
  27. /// </summary>
  28. public List<RoomInfo> BossRoom { get; } = new List<RoomInfo>();
  29. /// <summary>
  30. /// 随机数对象
  31. /// </summary>
  32. public SeedRandom Random { get; }
  33.  
  34. //用于标记地图上的坐标是否被占用
  35. private Grid<bool> _roomGrid { get; } = new Grid<bool>();
  36. //当前房间数量
  37. private int _count = 0;
  38. //房间id
  39. private int _id;
  40. //下一个房间类型
  41. private DungeonRoomType _nextRoomType = DungeonRoomType.Battle;
  42. //间隔
  43. private int _roomMinInterval = 6;
  44. private int _roomMaxInterval = 10;
  45.  
  46. //房间横轴分散程度
  47. private float _roomHorizontalMinDispersion = 0f;
  48. private float _roomHorizontalMaxDispersion = 0.7f;
  49.  
  50. //房间纵轴分散程度
  51. private float _roomVerticalMinDispersion = 0f;
  52. private float _roomVerticalMaxDispersion = 0.7f;
  53.  
  54. //区域限制
  55. private bool _enableLimitRange = true;
  56. private int _rangeX = 200;
  57. private int _rangeY = 200;
  58. //找房间失败次数, 过大则会关闭区域限制
  59. private int _maxFailCount = 10;
  60. private int _failCount = 0;
  61.  
  62. //最大尝试次数
  63. private int _maxTryCount = 10;
  64. private int _currMaxLayer = 0;
  65.  
  66. //地牢配置
  67. private DungeonConfig _config;
  68. private DungeonRoomGroup _roomGroup;
  69.  
  70. //指定只能生成的房间
  71. private static List<DungeonRoomSplit> _designatedRoom;
  72.  
  73. private enum GenerateRoomErrorCode
  74. {
  75. NoError,
  76. //超出区域
  77. OutArea,
  78. //没有合适的位置
  79. NoSuitableLocation
  80. // //碰到其他房间或过道
  81. // HasCollision,
  82. // //没有合适的门
  83. // NoProperDoor,
  84. }
  85. /// <summary>
  86. /// 用于调试, 设置生成器只能生成哪些房间
  87. /// </summary>
  88. public static void SetDesignatedRoom(List<DungeonRoomSplit> list)
  89. {
  90. _designatedRoom = new List<DungeonRoomSplit>(list);
  91. }
  92.  
  93. public DungeonGenerator(DungeonConfig config)
  94. {
  95. _config = config;
  96. _roomGroup = GameApplication.Instance.RoomConfig[config.GroupName];
  97. Random = new SeedRandom();
  98. GD.Print("创建地牢生成器, 随机种子: " + Random.Seed);
  99.  
  100. //验证该组是否满足生成地牢的条件
  101. if (_roomGroup.InletList.Count == 0)
  102. {
  103. throw new Exception("当前组'" + config.GroupName + "'中没有可用的起始房间, 不能生成地牢!");
  104. }
  105. //没有指定房间
  106. if (_designatedRoom == null || _designatedRoom.Count == 0)
  107. {
  108. if (_roomGroup.OutletList.Count == 0)
  109. {
  110. throw new Exception("当前组'" + config.GroupName + "'中没有可用的结束房间, 不能生成地牢!");
  111. }
  112. else if (_roomGroup.BattleList.Count == 0)
  113. {
  114. throw new Exception("当前组'" + config.GroupName + "'中没有可用的战斗房间, 不能生成地牢!");
  115. }
  116. }
  117.  
  118. _roomGroup.InitWeight(Random);
  119. }
  120.  
  121. /// <summary>
  122. /// 遍历所有房间
  123. /// </summary>
  124. public void EachRoom(Action<RoomInfo> cb)
  125. {
  126. EachRoom(StartRoomInfo, cb);
  127. }
  128.  
  129. private void EachRoom(RoomInfo roomInfo, Action<RoomInfo> cb)
  130. {
  131. if (roomInfo == null)
  132. {
  133. return;
  134. }
  135.  
  136. cb(roomInfo);
  137. foreach (var next in roomInfo.Next)
  138. {
  139. EachRoom(next, cb);
  140. }
  141. }
  142.  
  143. /// <summary>
  144. /// 生成房间
  145. /// </summary>
  146. public void Generate()
  147. {
  148. if (StartRoomInfo != null) return;
  149. CalcNextRoomType(null);
  150. //用于排除上一级房间
  151. var excludePrevRoom = new List<RoomInfo>();
  152. //上一个房间
  153. RoomInfo prevRoomInfo = null;
  154. var chainTryCount = 0;
  155. var chainMaxTryCount = 3;
  156.  
  157. //如果房间数量不够, 就一直生成
  158. while (_count < _config.RoomCount || EndRoomInfo == null)
  159. {
  160. var nextRoomType = GetNextRoomType();
  161. //上一个房间
  162. RoomInfo tempPrevRoomInfo;
  163. if (nextRoomType == DungeonRoomType.Inlet)
  164. {
  165. tempPrevRoomInfo = null;
  166. }
  167. else if (nextRoomType == DungeonRoomType.Boss)
  168. {
  169. tempPrevRoomInfo = FindMaxLayerRoom(excludePrevRoom);
  170. }
  171. else if (nextRoomType == DungeonRoomType.Outlet)
  172. {
  173. tempPrevRoomInfo = prevRoomInfo;
  174. }
  175. else if (nextRoomType == DungeonRoomType.Battle)
  176. {
  177. if (chainTryCount < chainMaxTryCount)
  178. {
  179. if (prevRoomInfo != null && prevRoomInfo.Layer > 6) //层数太高, 下一个房间生成在低层级
  180. {
  181. tempPrevRoomInfo = RoundRoomLessThanLayer(3);
  182. }
  183. else
  184. {
  185. tempPrevRoomInfo = prevRoomInfo;
  186. }
  187. }
  188. else
  189. {
  190. tempPrevRoomInfo = Random.RandomChoose(RoomInfos);
  191. }
  192. }
  193. else
  194. {
  195. tempPrevRoomInfo = Random.RandomChoose(RoomInfos);
  196. }
  197. //生成下一个房间
  198. var errorCode = GenerateRoom(tempPrevRoomInfo, nextRoomType, out var nextRoom);
  199. if (errorCode == GenerateRoomErrorCode.NoError) //生成成功
  200. {
  201. _failCount = 0;
  202. RoomInfos.Add(nextRoom);
  203. if (nextRoomType == DungeonRoomType.Inlet)
  204. {
  205. StartRoomInfo = nextRoom;
  206. }
  207. else if (nextRoomType == DungeonRoomType.Boss) //boss房间
  208. {
  209. BossRoom.Add(nextRoom);
  210. excludePrevRoom.Clear();
  211. }
  212. else if (nextRoomType == DungeonRoomType.Outlet)
  213. {
  214. EndRoomInfo = nextRoom;
  215. }
  216. else if (nextRoomType == DungeonRoomType.Battle)
  217. {
  218. chainTryCount = 0;
  219. chainMaxTryCount = Random.RandomRangeInt(1, 3);
  220. }
  221. prevRoomInfo = nextRoom;
  222. CalcNextRoomType(prevRoomInfo);
  223. }
  224. else //生成失败
  225. {
  226. if (nextRoomType == DungeonRoomType.Boss)
  227. {
  228. //生成boss房间成功
  229. excludePrevRoom.Add(tempPrevRoomInfo);
  230. if (excludePrevRoom.Count >= RoomInfos.Count)
  231. {
  232. //全都没找到合适的, 那就再来一遍
  233. excludePrevRoom.Clear();
  234. }
  235. }
  236. else if (nextRoomType == DungeonRoomType.Outlet)
  237. {
  238. //生成结束房间失败, 那么只能回滚boss房间
  239. if (prevRoomInfo != null)
  240. {
  241. var bossPrev = prevRoomInfo.Prev;
  242. BossRoom.Remove(prevRoomInfo);
  243. RollbackRoom(prevRoomInfo);
  244. CalcNextRoomType(bossPrev);
  245. prevRoomInfo = null;
  246. }
  247. }
  248. else if (nextRoomType == DungeonRoomType.Battle)
  249. {
  250. chainTryCount++;
  251. }
  252. GD.Print("生成第" + (_count + 1) + "个房间失败! 失败原因: " + errorCode);
  253. if (errorCode == GenerateRoomErrorCode.OutArea)
  254. {
  255. _failCount++;
  256. GD.Print("超出区域失败次数: " + _failCount);
  257. if (_failCount >= _maxFailCount)
  258. {
  259. _enableLimitRange = false;
  260. GD.Print("生成房间失败次数过多, 关闭区域限制!");
  261. }
  262. }
  263. }
  264. }
  265. _roomGrid.Clear();
  266. GD.Print("房间总数: " + RoomInfos.Count);
  267. }
  268.  
  269. //生成房间
  270. private GenerateRoomErrorCode GenerateRoom(RoomInfo prevRoomInfo, DungeonRoomType roomType, out RoomInfo resultRoomInfo)
  271. {
  272. // if (_count >= _config.RoomCount)
  273. // {
  274. // resultRoom = null;
  275. // return GenerateRoomErrorCode.RoomFull;
  276. // }
  277.  
  278. DungeonRoomSplit roomSplit;
  279. //没有指定房间
  280. if (roomType == DungeonRoomType.Inlet || _designatedRoom == null || _designatedRoom.Count == 0)
  281. {
  282. //随机选择一个房间
  283. var list = _roomGroup.GetRoomList(roomType);
  284. if (list.Count == 0) //如果没有指定类型的房间, 就生成战斗房间
  285. {
  286. roomSplit = _roomGroup.GetRandomRoom(DungeonRoomType.Battle);
  287. }
  288. else
  289. {
  290. roomSplit = _roomGroup.GetRandomRoom(roomType);
  291. }
  292. }
  293. else //指定了房间
  294. {
  295. roomSplit = Random.RandomChoose(_designatedRoom);
  296. }
  297. var room = new RoomInfo(_id, roomType, roomSplit);
  298.  
  299. //房间大小
  300. room.Size = new Vector2I((int)roomSplit.RoomInfo.Size.X, (int)roomSplit.RoomInfo.Size.Y);
  301.  
  302. if (prevRoomInfo != null) //表示这不是第一个房间, 就得判断当前位置下的房间是否被遮挡
  303. {
  304. room.Layer = prevRoomInfo.Layer + 1;
  305. if (_currMaxLayer < room.Layer)
  306. {
  307. _currMaxLayer = room.Layer;
  308. }
  309. //生成的位置可能会和上一个房间对不上, 需要多次尝试
  310. var tryCount = 0; //当前尝试次数
  311. var maxTryCount = _maxTryCount; //最大尝试次数
  312. if (roomType == DungeonRoomType.Outlet)
  313. {
  314. maxTryCount *= 3;
  315. }
  316. else if (roomType == DungeonRoomType.Boss)
  317. {
  318. maxTryCount *= 2;
  319. }
  320. for (; tryCount < maxTryCount; tryCount++)
  321. {
  322. var direction = Random.RandomRangeInt(0, 3);
  323. //房间间隔
  324. var space = Random.RandomRangeInt(_roomMinInterval, _roomMaxInterval);
  325. //中心偏移
  326. int offset;
  327. if (direction == 0 || direction == 2)
  328. {
  329. offset = Random.RandomRangeInt(-(int)(prevRoomInfo.Size.X * _roomVerticalMinDispersion),
  330. (int)(prevRoomInfo.Size.X * _roomVerticalMaxDispersion));
  331. }
  332. else
  333. {
  334. offset = Random.RandomRangeInt(-(int)(prevRoomInfo.Size.Y * _roomHorizontalMinDispersion),
  335. (int)(prevRoomInfo.Size.Y * _roomHorizontalMaxDispersion));
  336. }
  337.  
  338. //计算房间位置
  339. if (direction == 0) //上
  340. {
  341. room.Position = new Vector2I(prevRoomInfo.Position.X + offset,
  342. prevRoomInfo.Position.Y - room.Size.Y - space);
  343. }
  344. else if (direction == 1) //右
  345. {
  346. room.Position = new Vector2I(prevRoomInfo.Position.X + prevRoomInfo.Size.Y + space,
  347. prevRoomInfo.Position.Y + offset);
  348. }
  349. else if (direction == 2) //下
  350. {
  351. room.Position = new Vector2I(prevRoomInfo.Position.X + offset,
  352. prevRoomInfo.Position.Y + prevRoomInfo.Size.Y + space);
  353. }
  354. else if (direction == 3) //左
  355. {
  356. room.Position = new Vector2I(prevRoomInfo.Position.X - room.Size.X - space,
  357. prevRoomInfo.Position.Y + offset);
  358. }
  359.  
  360. //是否在限制区域内
  361. if (_enableLimitRange)
  362. {
  363. if (room.GetHorizontalStart() < -_rangeX || room.GetHorizontalEnd() > _rangeX ||
  364. room.GetVerticalStart() < -_rangeY || room.GetVerticalEnd() > _rangeY)
  365. {
  366. //超出区域, 直接跳出尝试的循环, 返回 null
  367. resultRoomInfo = null;
  368. return GenerateRoomErrorCode.OutArea;
  369. }
  370. }
  371.  
  372. //是否碰到其他房间或者过道
  373. if (_roomGrid.RectCollision(room.Position - new Vector2I(GameConfig.RoomSpace, GameConfig.RoomSpace), room.Size + new Vector2I(GameConfig.RoomSpace * 2, GameConfig.RoomSpace * 2)))
  374. {
  375. //碰到其他墙壁, 再一次尝试
  376. continue;
  377. //return GenerateRoomErrorCode.HasCollision;
  378. }
  379.  
  380. _roomGrid.SetRect(room.Position, room.Size, true);
  381.  
  382. //找门, 与上一个房间是否能连通
  383. if (!ConnectDoor(prevRoomInfo, room))
  384. {
  385. _roomGrid.RemoveRect(room.Position, room.Size);
  386. //房间过道没有连接上, 再一次尝试
  387. continue;
  388. //return GenerateRoomErrorCode.NoProperDoor;
  389. }
  390. break;
  391. }
  392.  
  393. //尝试次数用光了, 还没有找到合适的位置
  394. if (tryCount >= maxTryCount)
  395. {
  396. resultRoomInfo = null;
  397. return GenerateRoomErrorCode.NoSuitableLocation;
  398. }
  399. }
  400. else //第一个房间
  401. {
  402. room.Layer = 0;
  403. _roomGrid.SetRect(room.Position, room.Size, true);
  404. }
  405.  
  406. if (IsParticipateCounting(room))
  407. {
  408. _count++;
  409. }
  410. _id++;
  411. room.Prev = prevRoomInfo;
  412. if (prevRoomInfo != null)
  413. {
  414. prevRoomInfo.Next.Add(room);
  415. }
  416. resultRoomInfo = room;
  417. return GenerateRoomErrorCode.NoError;
  418. }
  419.  
  420. //判断房间是否参与计数
  421. private bool IsParticipateCounting(RoomInfo roomInfo)
  422. {
  423. return roomInfo.RoomType == DungeonRoomType.Battle || roomInfo.RoomType == DungeonRoomType.Boss;
  424. }
  425.  
  426. //计算下一个房间类型
  427. private void CalcNextRoomType(RoomInfo prev)
  428. {
  429. if (prev == null) //生成第一个房间
  430. {
  431. _nextRoomType = DungeonRoomType.Inlet;
  432. }
  433. else if (_count == _config.RoomCount - 1) //最后一个房间是boss房间
  434. {
  435. _nextRoomType = DungeonRoomType.Boss;
  436. }
  437. else if (_count >= _config.RoomCount) //结束房间
  438. {
  439. _nextRoomType = DungeonRoomType.Outlet;
  440. }
  441. else if (prev.RoomType == DungeonRoomType.Boss) //生成结束房间
  442. {
  443. _nextRoomType = DungeonRoomType.Outlet;
  444. }
  445. else
  446. {
  447. _nextRoomType = DungeonRoomType.Battle;
  448. }
  449. }
  450. //获取下一个房间类型
  451. private DungeonRoomType GetNextRoomType()
  452. {
  453. return _nextRoomType;
  454. }
  455.  
  456. //回滚一个房间
  457. private bool RollbackRoom(RoomInfo roomInfo)
  458. {
  459. if (roomInfo.Next.Count > 0)
  460. {
  461. GD.PrintErr("当前房间还有连接的子房间, 不能回滚!");
  462. return false;
  463. }
  464. //退掉占用的房间区域和过道占用区域
  465. _roomGrid.RemoveRect(roomInfo.Position, roomInfo.Size);
  466. foreach (var rect2 in roomInfo.AisleArea)
  467. {
  468. _roomGrid.RemoveRect(rect2.Position, rect2.Size);
  469. }
  470. //roomInfo.Doors[0].
  471. if (roomInfo.Prev != null)
  472. {
  473. roomInfo.Prev.Next.Remove(roomInfo);
  474. }
  475.  
  476. roomInfo.Prev = null;
  477. foreach (var roomInfoDoor in roomInfo.Doors)
  478. {
  479. var connectDoor = roomInfoDoor.ConnectDoor;
  480. connectDoor.RoomInfo.Doors.Remove(connectDoor);
  481. }
  482.  
  483. RoomInfos.Remove(roomInfo);
  484. roomInfo.Destroy();
  485.  
  486. if (IsParticipateCounting(roomInfo))
  487. {
  488. _count--;
  489. }
  490.  
  491. _id--;
  492. return true;
  493. }
  494.  
  495. /// <summary>
  496. /// 寻找层级最高的房间
  497. /// </summary>
  498. /// <param name="exclude">排除的房间</param>
  499. private RoomInfo FindMaxLayerRoom(List<RoomInfo> exclude)
  500. {
  501. RoomInfo temp = null;
  502. foreach (var roomInfo in RoomInfos)
  503. {
  504. if (temp == null || roomInfo.Layer > temp.Layer)
  505. {
  506. if (exclude == null || !exclude.Contains(roomInfo))
  507. {
  508. temp = roomInfo;
  509. }
  510. }
  511. }
  512.  
  513. return temp;
  514. }
  515.  
  516. /// <summary>
  517. /// 随机抽取层级小于 layer 的房间
  518. /// </summary>
  519. private RoomInfo RoundRoomLessThanLayer(int layer)
  520. {
  521. var list = new List<RoomInfo>();
  522. foreach (var roomInfo in RoomInfos)
  523. {
  524. if (roomInfo.Layer < layer)
  525. {
  526. list.Add(roomInfo);
  527. }
  528. }
  529.  
  530. return Random.RandomChoose(list);
  531. }
  532. /// <summary>
  533. /// 找两个房间的门
  534. /// </summary>
  535. private bool ConnectDoor(RoomInfo roomInfo, RoomInfo nextRoomInfo)
  536. {
  537. //门描述
  538. var roomDoor = new RoomDoorInfo();
  539. var nextRoomDoor = new RoomDoorInfo();
  540. roomDoor.RoomInfo = roomInfo;
  541. nextRoomDoor.RoomInfo = nextRoomInfo;
  542. roomDoor.ConnectRoom = nextRoomInfo;
  543. roomDoor.ConnectDoor = nextRoomDoor;
  544. nextRoomDoor.ConnectRoom = roomInfo;
  545. nextRoomDoor.ConnectDoor = roomDoor;
  546.  
  547. //先寻找直通门
  548. if (Random.RandomBoolean())
  549. {
  550. //直行通道, 优先横轴
  551. if (TryConnectHorizontalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor)
  552. || TryConnectVerticalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor))
  553. {
  554. return true;
  555. }
  556. }
  557. else
  558. {
  559. //直行通道, 优先纵轴
  560. if (TryConnectVerticalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor)
  561. || TryConnectHorizontalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor))
  562. {
  563. return true;
  564. }
  565. }
  566. //包含拐角的通道
  567. return TryConnectCrossDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor);
  568. }
  569.  
  570. /// <summary>
  571. /// 尝试寻找横轴方向上两个房间的连通的门, 只查找直线通道, 返回是否找到
  572. /// </summary>
  573. private bool TryConnectHorizontalDoor(RoomInfo roomInfo, RoomDoorInfo roomDoor, RoomInfo nextRoomInfo, RoomDoorInfo nextRoomDoor)
  574. {
  575. var overlapX = Mathf.Min(roomInfo.GetHorizontalEnd(), nextRoomInfo.GetHorizontalEnd()) -
  576. Mathf.Max(roomInfo.GetHorizontalStart(), nextRoomInfo.GetHorizontalStart());
  577. //这种情况下x轴有重叠
  578. if (overlapX >= 6)
  579. {
  580. //找到重叠区域
  581. var rangeList = FindPassage(roomInfo, nextRoomInfo,
  582. roomInfo.GetVerticalStart() < nextRoomInfo.GetVerticalStart() ? DoorDirection.S : DoorDirection.N);
  583. while (rangeList.Count > 0)
  584. {
  585. //找到重叠区域
  586. var range = Random.RandomChooseAndRemove(rangeList);
  587. var x = Random.RandomRangeInt(range.X, range.Y);
  588. if (roomInfo.GetVerticalStart() < nextRoomInfo.GetVerticalStart()) //room在上, nextRoom在下
  589. {
  590. roomDoor.Direction = DoorDirection.S;
  591. nextRoomDoor.Direction = DoorDirection.N;
  592. roomDoor.OriginPosition = new Vector2I(x, roomInfo.GetVerticalEnd());
  593. nextRoomDoor.OriginPosition = new Vector2I(x, nextRoomInfo.GetVerticalStart());
  594. }
  595. else //room在下, nextRoom在上
  596. {
  597. roomDoor.Direction = DoorDirection.N;
  598. nextRoomDoor.Direction = DoorDirection.S;
  599. roomDoor.OriginPosition = new Vector2I(x, roomInfo.GetVerticalStart());
  600. nextRoomDoor.OriginPosition = new Vector2I(x, nextRoomInfo.GetVerticalEnd());
  601. }
  602.  
  603. //判断门之间的通道是否有物体碰到
  604. if (!AddCorridorToGridRange(roomDoor, nextRoomDoor))
  605. {
  606. //此门不能连通
  607. continue;
  608. }
  609.  
  610. //没有撞到物体
  611. roomInfo.Doors.Add(roomDoor);
  612. nextRoomInfo.Doors.Add(nextRoomDoor);
  613. return true;
  614. }
  615. }
  616. return false;
  617. }
  618.  
  619. /// <summary>
  620. /// 尝试寻找纵轴方向上两个房间的连通的门, 只查找直线通道, 返回是否找到
  621. /// </summary>
  622. private bool TryConnectVerticalDoor(RoomInfo roomInfo, RoomDoorInfo roomDoor, RoomInfo nextRoomInfo, RoomDoorInfo nextRoomDoor)
  623. {
  624. var overlapY = Mathf.Min(roomInfo.GetVerticalEnd(), nextRoomInfo.GetVerticalEnd()) -
  625. Mathf.Max(roomInfo.GetVerticalStart(), nextRoomInfo.GetVerticalStart());
  626. //这种情况下y轴有重叠
  627. if (overlapY >= 6)
  628. {
  629. //找到重叠区域
  630. var rangeList = FindPassage(roomInfo, nextRoomInfo,
  631. roomInfo.GetHorizontalStart() < nextRoomInfo.GetHorizontalStart() ? DoorDirection.E : DoorDirection.W);
  632.  
  633. while (rangeList.Count > 0)
  634. {
  635. //找到重叠区域
  636. var range = Random.RandomChooseAndRemove(rangeList);
  637. var y = Random.RandomRangeInt(range.X, range.Y);
  638. if (roomInfo.GetHorizontalStart() < nextRoomInfo.GetHorizontalStart()) //room在左, nextRoom在右
  639. {
  640. roomDoor.Direction = DoorDirection.E;
  641. nextRoomDoor.Direction = DoorDirection.W;
  642. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalEnd(), y);
  643. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalStart(), y);
  644. }
  645. else //room在右, nextRoom在左
  646. {
  647. roomDoor.Direction = DoorDirection.W;
  648. nextRoomDoor.Direction = DoorDirection.E;
  649. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalStart(), y);
  650. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalEnd(), y);
  651. }
  652.  
  653. //判断门之间的通道是否有物体碰到
  654. if (!AddCorridorToGridRange(roomDoor, nextRoomDoor))
  655. {
  656. //此门不能连通
  657. continue;
  658. }
  659.  
  660. //没有撞到物体
  661. roomInfo.Doors.Add(roomDoor);
  662. nextRoomInfo.Doors.Add(nextRoomDoor);
  663. return true;
  664. }
  665. }
  666.  
  667. return false;
  668. }
  669.  
  670. /// <summary>
  671. /// 尝试寻找包含拐角的两个房间的连通的门, 返回是否找到
  672. /// </summary>
  673. private bool TryConnectCrossDoor(RoomInfo roomInfo, RoomDoorInfo roomDoor, RoomInfo nextRoomInfo, RoomDoorInfo nextRoomDoor)
  674. {
  675. //焦点
  676. Vector2I cross = default;
  677.  
  678. if (roomInfo.GetHorizontalStart() > nextRoomInfo.GetHorizontalStart())
  679. {
  680. if (roomInfo.GetVerticalStart() > nextRoomInfo.GetVerticalStart())
  681. {
  682. if (Random.RandomBoolean()) //↑ //→
  683. {
  684. if (!TryConnect_NE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  685. !TryConnect_WS_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  686. {
  687. return false;
  688. }
  689. }
  690. else //← //↓
  691. {
  692. if (!TryConnect_WS_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  693. !TryConnect_NE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  694. {
  695. return false;
  696. }
  697. }
  698. }
  699. else
  700. {
  701. if (Random.RandomBoolean()) //↓ //→
  702. {
  703. if (!TryConnect_SE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  704. !TryConnect_WN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  705. {
  706. return false;
  707. }
  708. }
  709. else //← //↑
  710. {
  711. if (!TryConnect_WN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  712. !TryConnect_SE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  713. {
  714. return false;
  715. }
  716. }
  717. }
  718. }
  719. else
  720. {
  721. if (roomInfo.GetVerticalStart() > nextRoomInfo.GetVerticalStart()) //→ //↓
  722. {
  723. if (Random.RandomBoolean())
  724. {
  725. if (!TryConnect_ES_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  726. !TryConnect_NW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  727. {
  728. return false;
  729. }
  730. }
  731. else //↑ //←
  732. {
  733. if (!TryConnect_NW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  734. !TryConnect_ES_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  735. {
  736. return false;
  737. }
  738. }
  739. }
  740. else
  741. {
  742. if (Random.RandomBoolean()) //→ //↑
  743. {
  744. if (!TryConnect_EN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  745. !TryConnect_SW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  746. {
  747. return false;
  748. }
  749. }
  750. else //↓ //←
  751. {
  752. if (!TryConnect_SW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  753. !TryConnect_EN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  754. {
  755. return false;
  756. }
  757. }
  758. }
  759. }
  760.  
  761. //判断门之间的通道是否有物体碰到
  762. if (!AddCorridorToGridRange(roomDoor, nextRoomDoor, cross))
  763. {
  764. //此门不能连通
  765. return false;
  766. }
  767.  
  768. roomDoor.HasCross = true;
  769. roomDoor.Cross = cross;
  770. nextRoomDoor.HasCross = true;
  771. nextRoomDoor.Cross = cross;
  772.  
  773. roomInfo.Doors.Add(roomDoor);
  774. nextRoomInfo.Doors.Add(nextRoomDoor);
  775. return true;
  776. }
  777.  
  778. private bool FindCrossPassage(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor,ref int offset1, ref int offset2)
  779. {
  780. var room1 = roomInfo.RoomSplit.RoomInfo;
  781. var room2 = nextRoomInfo.RoomSplit.RoomInfo;
  782. int? temp1 = null;
  783. int? temp2 = null;
  784.  
  785. foreach (var areaInfo1 in room1.GetCompletionDoorArea())
  786. {
  787. if (areaInfo1.Direction == roomDoor.Direction)
  788. {
  789. FindCrossPassage_Area(areaInfo1, roomInfo, nextRoomInfo, ref temp1);
  790. }
  791. }
  792. if (temp1 == null)
  793. {
  794. return false;
  795. }
  796.  
  797. foreach (var areaInfo2 in room2.GetCompletionDoorArea())
  798. {
  799. if (areaInfo2.Direction == nextRoomDoor.Direction)
  800. {
  801. FindCrossPassage_Area(areaInfo2, nextRoomInfo, roomInfo, ref temp2);
  802. }
  803. }
  804.  
  805. if (temp2 == null)
  806. {
  807. return false;
  808. }
  809. offset1 = temp1.Value;
  810. offset2 = temp2.Value;
  811. return true;
  812. }
  813.  
  814. private void FindCrossPassage_Area(DoorAreaInfo areaInfo, RoomInfo room1, RoomInfo room2, ref int? areaRange)
  815. {
  816. if (areaInfo.Direction == DoorDirection.N || areaInfo.Direction == DoorDirection.S) //纵向门
  817. {
  818. var num = room1.GetHorizontalStart();
  819. var p1 = num + areaInfo.Start / GameConfig.TileCellSize;
  820. var p2 = num + areaInfo.End / GameConfig.TileCellSize;
  821.  
  822. if (room1.Position.X > room2.Position.X)
  823. {
  824. var range = CalcOverlapRange(room2.GetHorizontalEnd() + GameConfig.RoomSpace,
  825. room1.GetHorizontalEnd(), p1, p2);
  826. //交集范围够生成门
  827. if (range.Y - range.X >= GameConfig.CorridorWidth)
  828. {
  829. // var tempRange = new Vector2I(Mathf.Abs(room1.Position.X - (int)range.X),
  830. // Mathf.Abs(room1.Position.X - (int)range.Y) - GameConfig.CorridorWidth);
  831. var rangeValue = Mathf.Abs(room1.Position.X - (int)range.X);
  832.  
  833. if (areaRange == null || rangeValue < areaRange)
  834. {
  835. areaRange = rangeValue;
  836. }
  837. }
  838. }
  839. else
  840. {
  841. var range = CalcOverlapRange(room1.GetHorizontalStart(),
  842. room2.GetHorizontalStart() - + GameConfig.RoomSpace, p1, p2);
  843. //交集范围够生成门
  844. if (range.Y - range.X >= GameConfig.CorridorWidth)
  845. {
  846. // var tempRange = new Vector2I(Mathf.Abs(room1.Position.X - (int)range.X),
  847. // Mathf.Abs(room1.Position.X - (int)range.Y) - GameConfig.CorridorWidth);
  848.  
  849. var rangeValue = Mathf.Abs(room1.Position.X - (int)range.Y) - GameConfig.CorridorWidth;
  850.  
  851. if (areaRange == null || rangeValue > areaRange)
  852. {
  853. areaRange = rangeValue;
  854. }
  855. }
  856. }
  857. }
  858. else //横向门
  859. {
  860. var num = room1.GetVerticalStart();
  861. var p1 = num + areaInfo.Start / GameConfig.TileCellSize;
  862. var p2 = num + areaInfo.End / GameConfig.TileCellSize;
  863.  
  864. if (room1.Position.Y > room2.Position.Y)
  865. {
  866. var range = CalcOverlapRange(room2.GetVerticalEnd() + GameConfig.RoomSpace,
  867. room1.GetVerticalEnd(), p1, p2);
  868. //交集范围够生成门
  869. if (range.Y - range.X >= GameConfig.CorridorWidth)
  870. {
  871. // var tempRange = new Vector2I(Mathf.Abs(room1.Position.Y - (int)range.X),
  872. // Mathf.Abs(room1.Position.Y - (int)range.Y) - GameConfig.CorridorWidth);
  873.  
  874. var rangeValue = Mathf.Abs(room1.Position.Y - (int)range.X);
  875.  
  876. if (areaRange == null || rangeValue < areaRange)
  877. {
  878. areaRange = rangeValue;
  879. }
  880. }
  881. }
  882. else
  883. {
  884. var range = CalcOverlapRange(room1.GetVerticalStart(),
  885. room2.GetVerticalStart() - GameConfig.RoomSpace, p1, p2);
  886. //交集范围够生成门
  887. if (range.Y - range.X >= GameConfig.CorridorWidth)
  888. {
  889. // var tempRange = new Vector2I(Mathf.Abs(room1.Position.Y - (int)range.X),
  890. // Mathf.Abs(room1.Position.Y - (int)range.Y) - GameConfig.CorridorWidth);
  891. var rangeValue = Mathf.Abs(room1.Position.Y - (int)range.Y) - GameConfig.CorridorWidth;
  892.  
  893. if (areaRange == null || rangeValue > areaRange)
  894. {
  895. areaRange = rangeValue;
  896. }
  897. }
  898. }
  899. }
  900. }
  901.  
  902. private bool TryConnect_NE_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  903. {
  904. var offset1 = 0;
  905. var offset2 = 0;
  906. roomDoor.Direction = DoorDirection.N; //↑
  907. nextRoomDoor.Direction = DoorDirection.E; //→
  908.  
  909. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  910. {
  911. return false;
  912. }
  913. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalStart() + offset1, roomInfo.GetVerticalStart());
  914. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalEnd(),
  915. nextRoomInfo.GetVerticalStart() + offset2);
  916. cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  917. return true;
  918. }
  919.  
  920. private bool TryConnect_WS_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  921. {
  922. //ok
  923. var offset1 = 0;
  924. var offset2 = 0;
  925. roomDoor.Direction = DoorDirection.W; //←
  926. nextRoomDoor.Direction = DoorDirection.S; //↓
  927. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  928. {
  929. return false;
  930. }
  931. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalStart(), roomInfo.GetVerticalStart() + offset1);
  932. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalStart() + offset2, nextRoomInfo.GetVerticalEnd());
  933. cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  934. return true;
  935. }
  936.  
  937. private bool TryConnect_SE_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  938. {
  939. var offset1 = 0;
  940. var offset2 = 0;
  941. roomDoor.Direction = DoorDirection.S; //↓
  942. nextRoomDoor.Direction = DoorDirection.E; //→
  943. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  944. {
  945. return false;
  946. }
  947.  
  948. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalStart() + offset1, roomInfo.GetVerticalEnd());
  949. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalEnd(),
  950. nextRoomInfo.GetVerticalStart() + offset2);
  951. cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  952. return true;
  953. }
  954.  
  955. private bool TryConnect_WN_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  956. {
  957. var offset1 = 0;
  958. var offset2 = 0;
  959. roomDoor.Direction = DoorDirection.W; //←
  960. nextRoomDoor.Direction = DoorDirection.N; //↑
  961. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  962. {
  963. return false;
  964. }
  965.  
  966. roomDoor.OriginPosition =
  967. new Vector2I(roomInfo.GetHorizontalStart(), roomInfo.GetVerticalStart() + offset1); //
  968. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalStart() + offset2,
  969. nextRoomInfo.GetVerticalStart());
  970. cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  971. return true;
  972. }
  973. private bool TryConnect_ES_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  974. {
  975. var offset1 = 0;
  976. var offset2 = 0;
  977. roomDoor.Direction = DoorDirection.E; //→
  978. nextRoomDoor.Direction = DoorDirection.S; //↓
  979.  
  980. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  981. {
  982. return false;
  983. }
  984. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalEnd(), roomInfo.GetVerticalStart() + offset1);
  985. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalStart() + offset2,
  986. nextRoomInfo.GetVerticalEnd());
  987. cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  988. return true;
  989. }
  990. private bool TryConnect_NW_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  991. {
  992. var offset1 = 0;
  993. var offset2 = 0;
  994. roomDoor.Direction = DoorDirection.N; //↑
  995. nextRoomDoor.Direction = DoorDirection.W; //←
  996.  
  997. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  998. {
  999. return false;
  1000. }
  1001. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalStart() + offset1, roomInfo.GetVerticalStart());
  1002. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalStart(),
  1003. nextRoomInfo.GetVerticalStart() + offset2);
  1004. cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  1005. return true;
  1006. }
  1007. private bool TryConnect_EN_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1008. {
  1009. var offset1 = 0;
  1010. var offset2 = 0;
  1011. roomDoor.Direction = DoorDirection.E; //→
  1012. nextRoomDoor.Direction = DoorDirection.N; //↑
  1013.  
  1014. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1015. {
  1016. return false;
  1017. }
  1018. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalEnd(),
  1019. roomInfo.GetVerticalStart() + offset1);
  1020. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalStart() + offset2, nextRoomInfo.GetVerticalStart());
  1021. cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  1022. return true;
  1023. }
  1024.  
  1025. private bool TryConnect_SW_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1026. {
  1027. var offset1 = 0;
  1028. var offset2 = 0;
  1029. roomDoor.Direction = DoorDirection.S; //↓
  1030. nextRoomDoor.Direction = DoorDirection.W; //←
  1031.  
  1032. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1033. {
  1034. return false;
  1035. }
  1036. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalStart() + offset1,
  1037. roomInfo.GetVerticalEnd());
  1038. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalStart(), nextRoomInfo.GetVerticalStart() + offset2);
  1039. cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  1040. return true;
  1041. }
  1042.  
  1043. /// <summary>
  1044. /// 查找房间的连接通道, 函数返回是否找到对应的门, 通过 result 返回 x/y 轴坐标
  1045. /// </summary>
  1046. /// <param name="roomInfo">第一个房间</param>
  1047. /// <param name="nextRoomInfo">第二个房间</param>
  1048. /// <param name="direction">第一个房间连接方向</param>
  1049. private List<Vector2I> FindPassage(RoomInfo roomInfo, RoomInfo nextRoomInfo, DoorDirection direction)
  1050. {
  1051. var room1 = roomInfo.RoomSplit.RoomInfo;
  1052. var room2 = nextRoomInfo.RoomSplit.RoomInfo;
  1053. //用于存储符合生成条件的区域
  1054. var rangeList = new List<Vector2I>();
  1055. foreach (var doorAreaInfo1 in room1.GetCompletionDoorArea())
  1056. {
  1057. if (doorAreaInfo1.Direction == direction)
  1058. {
  1059. //第二个门的方向
  1060. var direction2 = GetReverseDirection(direction);
  1061. foreach (var doorAreaInfo2 in room2.GetCompletionDoorArea())
  1062. {
  1063. if (doorAreaInfo2.Direction == direction2)
  1064. {
  1065. Vector2 range;
  1066. if (direction == DoorDirection.E || direction == DoorDirection.W) //第二个门向← 或者 第二个门向→
  1067. {
  1068. range = CalcOverlapRange(
  1069. roomInfo.GetVerticalStart() * GameConfig.TileCellSize + doorAreaInfo1.Start, roomInfo.GetVerticalStart() * GameConfig.TileCellSize + doorAreaInfo1.End,
  1070. nextRoomInfo.GetVerticalStart() * GameConfig.TileCellSize + doorAreaInfo2.Start, nextRoomInfo.GetVerticalStart() * GameConfig.TileCellSize + doorAreaInfo2.End
  1071. );
  1072. }
  1073. else //第二个门向↑ 或者 第二个门向↓
  1074. {
  1075. range = CalcOverlapRange(
  1076. roomInfo.GetHorizontalStart() * GameConfig.TileCellSize + doorAreaInfo1.Start, roomInfo.GetHorizontalStart() * GameConfig.TileCellSize + doorAreaInfo1.End,
  1077. nextRoomInfo.GetHorizontalStart() * GameConfig.TileCellSize + doorAreaInfo2.Start, nextRoomInfo.GetHorizontalStart() * GameConfig.TileCellSize + doorAreaInfo2.End
  1078. );
  1079. }
  1080. //交集范围够生成门
  1081. if (range.Y - range.X >= GameConfig.CorridorWidth * GameConfig.TileCellSize)
  1082. {
  1083. rangeList.Add(new Vector2I((int)(range.X / GameConfig.TileCellSize), (int)(range.Y / GameConfig.TileCellSize) - GameConfig.CorridorWidth));
  1084. }
  1085. }
  1086. }
  1087. }
  1088. }
  1089. return rangeList;
  1090. }
  1091. /// <summary>
  1092. /// 用于计算重叠区域坐标, 可以理解为一维轴上4个点的中间两个点, 返回的x为起始点, y为结束点
  1093. /// </summary>
  1094. private Vector2 CalcOverlapRange(float start1, float end1, float start2, float end2)
  1095. {
  1096. return new Vector2(Mathf.Max(start1, start2), Mathf.Min(end1, end2));
  1097. }
  1098.  
  1099. /// <summary>
  1100. /// 返回 p1 - p2 是否在 start - end 范围内
  1101. /// </summary>
  1102. private bool IsInRange(float start, float end, float p1, float p2)
  1103. {
  1104. return p1 >= start && p2 <= end;
  1105. }
  1106. //返回指定方向的反方向
  1107. //0上, 1右, 2下, 3左
  1108. private int GetReverseDirection(int direction)
  1109. {
  1110. switch (direction)
  1111. {
  1112. case 0: return 2;
  1113. case 1: return 3;
  1114. case 2: return 0;
  1115. case 3: return 1;
  1116. }
  1117.  
  1118. return 2;
  1119. }
  1120. //返回参数方向的反方向
  1121. private DoorDirection GetReverseDirection(DoorDirection direction)
  1122. {
  1123. switch (direction)
  1124. {
  1125. case DoorDirection.E:
  1126. return DoorDirection.W;
  1127. case DoorDirection.W:
  1128. return DoorDirection.E;
  1129. case DoorDirection.S:
  1130. return DoorDirection.N;
  1131. case DoorDirection.N:
  1132. return DoorDirection.S;
  1133. }
  1134.  
  1135. return DoorDirection.S;
  1136. }
  1137.  
  1138. //将两个门间的过道占用数据存入RoomGrid
  1139. private bool AddCorridorToGridRange(RoomDoorInfo door1, RoomDoorInfo door2)
  1140. {
  1141. var point1 = door1.OriginPosition;
  1142. var point2 = door2.OriginPosition;
  1143. var pos = new Vector2I(Mathf.Min(point1.X, point2.X), Mathf.Min(point1.Y, point2.Y));
  1144. var size = new Vector2I(
  1145. point1.X == point2.X ? GameConfig.CorridorWidth : Mathf.Abs(point1.X - point2.X),
  1146. point1.Y == point2.Y ? GameConfig.CorridorWidth : Mathf.Abs(point1.Y - point2.Y)
  1147. );
  1148.  
  1149. Vector2I collPos;
  1150. Vector2I collSize;
  1151. if (point1.X == point2.X) //纵向加宽, 防止贴到其它墙
  1152. {
  1153. collPos = new Vector2I(pos.X - GameConfig.RoomSpace, pos.Y);
  1154. collSize = new Vector2I(size.X + GameConfig.RoomSpace * 2, size.Y);
  1155. }
  1156. else //横向加宽, 防止贴到其它墙
  1157. {
  1158. collPos = new Vector2I(pos.X, pos.Y - GameConfig.RoomSpace);
  1159. collSize = new Vector2I(size.X, size.Y + GameConfig.RoomSpace * 2);
  1160. }
  1161.  
  1162. if (_roomGrid.RectCollision(collPos, collSize))
  1163. {
  1164. return false;
  1165. }
  1166.  
  1167. door2.RoomInfo.AisleArea.Add(new Rect2I(pos, size));
  1168. _roomGrid.SetRect(pos, size, true);
  1169. return true;
  1170. }
  1171.  
  1172. //将两个门间的过道占用数据存入RoomGrid, 该重载加入拐角点
  1173. private bool AddCorridorToGridRange(RoomDoorInfo door1, RoomDoorInfo door2, Vector2I cross)
  1174. {
  1175. var point1 = door1.OriginPosition;
  1176. var point2 = door2.OriginPosition;
  1177. var pos1 = new Vector2I(Mathf.Min(point1.X, cross.X), Mathf.Min(point1.Y, cross.Y));
  1178. var size1 = new Vector2I(
  1179. point1.X == cross.X ? GameConfig.CorridorWidth : Mathf.Abs(point1.X - cross.X),
  1180. point1.Y == cross.Y ? GameConfig.CorridorWidth : Mathf.Abs(point1.Y - cross.Y)
  1181. );
  1182. var pos2 = new Vector2I(Mathf.Min(point2.X, cross.X), Mathf.Min(point2.Y, cross.Y));
  1183. var size2 = new Vector2I(
  1184. point2.X == cross.X ? GameConfig.CorridorWidth : Mathf.Abs(point2.X - cross.X),
  1185. point2.Y == cross.Y ? GameConfig.CorridorWidth : Mathf.Abs(point2.Y - cross.Y)
  1186. );
  1187.  
  1188. Vector2I collPos1;
  1189. Vector2I collSize1;
  1190. if (point1.X == cross.X) //纵向加宽, 防止贴到其它墙
  1191. {
  1192. collPos1 = new Vector2I(pos1.X - GameConfig.RoomSpace, pos1.Y);
  1193. collSize1 = new Vector2I(size1.X + GameConfig.RoomSpace * 2, size1.Y);
  1194. }
  1195. else //横向加宽, 防止贴到其它墙
  1196. {
  1197. collPos1 = new Vector2I(pos1.X, pos1.Y - GameConfig.RoomSpace);
  1198. collSize1 = new Vector2I(size1.X, size1.Y + GameConfig.RoomSpace * 2);
  1199. }
  1200.  
  1201. if (_roomGrid.RectCollision(collPos1, collSize1))
  1202. {
  1203. return false;
  1204. }
  1205.  
  1206. Vector2I collPos2;
  1207. Vector2I collSize2;
  1208. if (point2.X == cross.X) //纵向加宽, 防止贴到其它墙
  1209. {
  1210. collPos2 = new Vector2I(pos2.X - GameConfig.RoomSpace, pos2.Y);
  1211. collSize2 = new Vector2I(size2.X + GameConfig.RoomSpace * 2, size2.Y);
  1212. }
  1213. else //横向加宽, 防止贴到其它墙
  1214. {
  1215. collPos2 = new Vector2I(pos2.X, pos2.Y - GameConfig.RoomSpace);
  1216. collSize2 = new Vector2I(size2.X, size2.Y + GameConfig.RoomSpace * 2);
  1217. }
  1218.  
  1219. if (_roomGrid.RectCollision(collPos2, collSize2))
  1220. {
  1221. return false;
  1222. }
  1223.  
  1224. door2.RoomInfo.AisleArea.Add(new Rect2I(pos1, size1));
  1225. door2.RoomInfo.AisleArea.Add(new Rect2I(pos2, size2));
  1226. _roomGrid.SetRect(pos1, size1, true);
  1227. _roomGrid.SetRect(pos2, size2, true);
  1228. return true;
  1229. }
  1230. }