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