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