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