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