Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / DungeonGenerator.cs
@小李xl 小李xl on 25 Jan 2024 49 KB 生成奖励房间
  1.  
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using Godot;
  6.  
  7. /// <summary>
  8. /// 地牢生成器
  9. /// </summary>
  10. public class DungeonGenerator
  11. {
  12. /// <summary>
  13. /// 所有生成的房间, 调用过 Generate() 函数才能获取到值
  14. /// </summary>
  15. public List<RoomInfo> RoomInfos { get; } = new List<RoomInfo>();
  16.  
  17. /// <summary>
  18. /// 起始房间
  19. /// </summary>
  20. public RoomInfo StartRoomInfo { get; private set; }
  21.  
  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 = 2000;
  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. if (direction == RoomDirection.Up || direction == RoomDirection.Down)
  284. {
  285. space += 1;
  286. }
  287. //中心偏移
  288. var offset = _rule.GetNextRoomOffset(prevRoom, roomType, direction);
  289.  
  290. //计算房间位置
  291. if (direction == RoomDirection.Up) //上
  292. {
  293. room.Position = new Vector2I(prevRoom.Position.X + offset,
  294. prevRoom.Position.Y - room.Size.Y - space);
  295. }
  296. else if (direction == RoomDirection.Right) //右
  297. {
  298. room.Position = new Vector2I(prevRoom.Position.X + prevRoom.Size.Y + space,
  299. prevRoom.Position.Y + offset);
  300. }
  301. else if (direction == RoomDirection.Down) //下
  302. {
  303. room.Position = new Vector2I(prevRoom.Position.X + offset,
  304. prevRoom.Position.Y + prevRoom.Size.Y + space);
  305. }
  306. else if (direction == RoomDirection.Left) //左
  307. {
  308. room.Position = new Vector2I(prevRoom.Position.X - room.Size.X - space,
  309. prevRoom.Position.Y + offset);
  310. }
  311.  
  312. //是否在限制区域内
  313. if (Config.EnableLimitRange)
  314. {
  315. if (room.GetHorizontalStart() < -_rangeX || room.GetHorizontalEnd() > _rangeX ||
  316. room.GetVerticalStart() < -_rangeY || room.GetVerticalEnd() > _rangeY)
  317. {
  318. //超出区域, 直接跳出尝试的循环, 返回 null
  319. resultRoomInfo = null;
  320. return GenerateRoomErrorCode.OutArea;
  321. }
  322. }
  323.  
  324. //是否碰到其他房间或者过道
  325. if (_roomGrid.RectCollision(room.Position - Vector2I.One, room.Size + new Vector2I(2, 2)))
  326. {
  327. //碰到其他墙壁, 再一次尝试
  328. continue;
  329. //return GenerateRoomErrorCode.HasCollision;
  330. }
  331. _roomGrid.SetRect(room.Position, room.Size, true);
  332.  
  333. //找门, 与上一个房间是否能连通
  334. if (!ConnectDoor(prevRoom, room))
  335. {
  336. _roomGrid.RemoveRect(room.Position, room.Size);
  337. //Debug.Log("链接通道失败");
  338. //房间过道没有连接上, 再一次尝试
  339. continue;
  340. //return GenerateRoomErrorCode.NoProperDoor;
  341. }
  342. break;
  343. }
  344.  
  345. //尝试次数用光了, 还没有找到合适的位置
  346. if (tryCount >= maxTryCount)
  347. {
  348. resultRoomInfo = null;
  349. return GenerateRoomErrorCode.NoSuitableLocation;
  350. }
  351. }
  352. else //第一个房间
  353. {
  354. room.Layer = 0;
  355. _roomGrid.SetRect(room.Position, room.Size, true);
  356. }
  357. _id++;
  358. room.Prev = prevRoom;
  359. if (prevRoom != null)
  360. {
  361. prevRoom.Next.Add(room);
  362. }
  363. resultRoomInfo = room;
  364. return GenerateRoomErrorCode.NoError;
  365. }
  366.  
  367. /// <summary>
  368. /// 设置上一个房间
  369. /// </summary>
  370. public void SetPrevRoom(RoomInfo roomInfo)
  371. {
  372. prevRoomInfo = roomInfo;
  373. }
  374.  
  375. /// <summary>
  376. /// 回滚一个房间
  377. /// </summary>
  378. public bool RollbackRoom(RoomInfo roomInfo)
  379. {
  380. if (roomInfo.Next.Count > 0)
  381. {
  382. Debug.LogError("当前房间还有连接的子房间, 不能回滚!");
  383. return false;
  384. }
  385.  
  386. if (!roomInfo.CanRollback)
  387. {
  388. Debug.LogError("当前房间不能回滚!");
  389. return false;
  390. }
  391. var prevRoom = roomInfo.Prev;
  392. //退掉占用的房间区域和过道占用区域
  393. _roomGrid.RemoveRect(roomInfo.Position, roomInfo.Size);
  394. foreach (var rect2 in roomInfo.AisleArea)
  395. {
  396. _roomGrid.RemoveRect(rect2.Position, rect2.Size);
  397. }
  398. //roomInfo.Doors[0].
  399. if (prevRoom != null)
  400. {
  401. roomInfo.Prev.Next.Remove(roomInfo);
  402. }
  403.  
  404. roomInfo.Prev = null;
  405. foreach (var roomInfoDoor in roomInfo.Doors)
  406. {
  407. var connectDoor = roomInfoDoor.ConnectDoor;
  408. connectDoor.RoomInfo.Doors.Remove(connectDoor);
  409. }
  410.  
  411. RoomInfos.Remove(roomInfo);
  412. switch (roomInfo.RoomType)
  413. {
  414. case DungeonRoomType.Battle:
  415. BattleRoomInfos.Remove(roomInfo);
  416. break;
  417. case DungeonRoomType.Inlet:
  418. StartRoomInfo = null;
  419. break;
  420. case DungeonRoomType.Outlet:
  421. EndRoomInfos.Remove(roomInfo);
  422. break;
  423. case DungeonRoomType.Boss:
  424. BossRoomInfos.Remove(roomInfo);
  425. break;
  426. case DungeonRoomType.Reward:
  427. RewardRoomInfos.Remove(roomInfo);
  428. break;
  429. case DungeonRoomType.Shop:
  430. ShopRoomInfos.Remove(roomInfo);
  431. break;
  432. case DungeonRoomType.Event:
  433. break;
  434. }
  435. roomInfo.Destroy();
  436. _id--;
  437. _nextRoomType = DungeonRoomType.None;
  438. SetPrevRoom(prevRoom);
  439. return true;
  440. }
  441.  
  442. /// <summary>
  443. /// 寻找层级最高的房间
  444. /// </summary>
  445. /// <param name="roomType">指定房间类型, 如果传 None 则表示选择所有类型房间</param>
  446. /// <param name="exclude">排除的房间</param>
  447. public RoomInfo FindMaxLayerRoom(DungeonRoomType roomType, List<RoomInfo> exclude = null)
  448. {
  449. RoomInfo temp = null;
  450. foreach (var roomInfo in RoomInfos)
  451. {
  452. if (roomInfo.CanRollback)
  453. {
  454. continue;
  455. }
  456. if ((temp == null || roomInfo.Layer > temp.Layer) && (roomType == DungeonRoomType.None || (roomInfo.RoomType & roomType) != DungeonRoomType.None) && (exclude == null || !exclude.Contains(roomInfo)))
  457. {
  458. temp = roomInfo;
  459. }
  460. }
  461.  
  462. return temp;
  463. }
  464.  
  465. /// <summary>
  466. /// 随机抽取层级小于 layer 的房间
  467. /// </summary>
  468. /// <param name="roomType">指定房间类型, 如果传 None 则表示选择所有类型房间</param>
  469. /// <param name="layer"></param>
  470. /// <param name="exclude">排除的房间</param>
  471. public RoomInfo RandomRoomLessThanLayer(DungeonRoomType roomType, int layer, List<RoomInfo> exclude = null)
  472. {
  473. _tempList.Clear();
  474. foreach (var roomInfo in RoomInfos)
  475. {
  476. if (roomInfo.CanRollback)
  477. {
  478. continue;
  479. }
  480. if (roomInfo.Layer < layer && (roomType == DungeonRoomType.None || (roomInfo.RoomType & roomType) != DungeonRoomType.None) && (exclude == null || !exclude.Contains(roomInfo)))
  481. {
  482. _tempList.Add(roomInfo);
  483. }
  484. }
  485.  
  486. return Random.RandomChoose(_tempList);
  487. }
  488. /// <summary>
  489. /// 随机抽取层级大于 layer 的房间
  490. /// </summary>
  491. /// <param name="roomType">指定房间类型, 如果传 None 则表示选择所有类型房间</param>
  492. /// <param name="layer"></param>
  493. /// <param name="exclude">排除的房间</param>
  494. public RoomInfo RandomRoomGreaterThanLayer(DungeonRoomType roomType, int layer, List<RoomInfo> exclude = null)
  495. {
  496. _tempList.Clear();
  497. foreach (var roomInfo in RoomInfos)
  498. {
  499. if (roomInfo.CanRollback)
  500. {
  501. continue;
  502. }
  503. if (roomInfo.Layer > layer && (roomType == DungeonRoomType.None || (roomInfo.RoomType & roomType) != DungeonRoomType.None) && (exclude == null || !exclude.Contains(roomInfo)))
  504. {
  505. _tempList.Add(roomInfo);
  506. }
  507. }
  508.  
  509. return Random.RandomChoose(_tempList);
  510. }
  511. /// <summary>
  512. /// 随机抽取房间
  513. /// </summary>
  514. /// <param name="roomType">指定房间类型, 如果传 None 则表示选择所有类型房间</param>
  515. public RoomInfo GetRandomRoom(DungeonRoomType roomType)
  516. {
  517. _tempList.Clear();
  518. foreach (var roomInfo in RoomInfos)
  519. {
  520. if (roomInfo.CanRollback)
  521. {
  522. continue;
  523. }
  524.  
  525. if (roomType == DungeonRoomType.None || (roomInfo.RoomType & roomType) != DungeonRoomType.None)
  526. {
  527. _tempList.Add(roomInfo);
  528. }
  529. }
  530.  
  531. return Random.RandomChoose(_tempList);
  532. }
  533.  
  534. /// <summary>
  535. /// 提交所有可以回滚的房间
  536. /// </summary>
  537. public void SubmitCanRollbackRoom()
  538. {
  539. foreach (var roomInfo in RoomInfos)
  540. {
  541. roomInfo.CanRollback = false;
  542. }
  543. }
  544. /// <summary>
  545. /// 找两个房间的门
  546. /// </summary>
  547. private bool ConnectDoor(RoomInfo roomInfo, RoomInfo nextRoomInfo)
  548. {
  549. //门描述
  550. var roomDoor = new RoomDoorInfo();
  551. var nextRoomDoor = new RoomDoorInfo();
  552. roomDoor.RoomInfo = roomInfo;
  553. roomDoor.IsForward = true;
  554. nextRoomDoor.RoomInfo = nextRoomInfo;
  555. roomDoor.ConnectRoom = nextRoomInfo;
  556. roomDoor.ConnectDoor = nextRoomDoor;
  557. nextRoomDoor.ConnectRoom = roomInfo;
  558. nextRoomDoor.ConnectDoor = roomDoor;
  559.  
  560. //先寻找直通门
  561. if (Random.RandomBoolean())
  562. {
  563. //直行通道, 优先横轴
  564. if (TryConnectHorizontalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor)
  565. || TryConnectVerticalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor))
  566. {
  567. return true;
  568. }
  569. }
  570. else
  571. {
  572. //直行通道, 优先纵轴
  573. if (TryConnectVerticalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor)
  574. || TryConnectHorizontalDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor))
  575. {
  576. return true;
  577. }
  578. }
  579. //包含拐角的通道
  580. return TryConnectCrossDoor(roomInfo, roomDoor, nextRoomInfo, nextRoomDoor);
  581. }
  582.  
  583. /// <summary>
  584. /// 尝试寻找横轴方向上两个房间的连通的门, 只查找直线通道, 返回是否找到
  585. /// </summary>
  586. private bool TryConnectHorizontalDoor(RoomInfo roomInfo, RoomDoorInfo roomDoor, RoomInfo nextRoomInfo, RoomDoorInfo nextRoomDoor)
  587. {
  588. var overlapX = Mathf.Min(roomInfo.GetHorizontalEnd(), nextRoomInfo.GetHorizontalEnd()) -
  589. Mathf.Max(roomInfo.GetHorizontalStart(), nextRoomInfo.GetHorizontalStart());
  590. //这种情况下x轴有重叠
  591. if (overlapX >= 6)
  592. {
  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. else //room在下, nextRoom在上
  609. {
  610. roomDoor.Direction = DoorDirection.N;
  611. nextRoomDoor.Direction = DoorDirection.S;
  612. roomDoor.OriginPosition = new Vector2I(x, roomInfo.GetVerticalDoorStart());
  613. nextRoomDoor.OriginPosition = new Vector2I(x, nextRoomInfo.GetVerticalDoorEnd());
  614. }
  615.  
  616. //判断门之间的通道是否有物体碰到
  617. if (!AddCorridorToGridRange(roomDoor, nextRoomDoor))
  618. {
  619. //此门不能连通
  620. continue;
  621. }
  622.  
  623. //没有撞到物体
  624. roomInfo.Doors.Add(roomDoor);
  625. nextRoomInfo.Doors.Add(nextRoomDoor);
  626. return true;
  627. }
  628. }
  629. return false;
  630. }
  631.  
  632. /// <summary>
  633. /// 尝试寻找纵轴方向上两个房间的连通的门, 只查找直线通道, 返回是否找到
  634. /// </summary>
  635. private bool TryConnectVerticalDoor(RoomInfo roomInfo, RoomDoorInfo roomDoor, RoomInfo nextRoomInfo, RoomDoorInfo nextRoomDoor)
  636. {
  637. var overlapY = Mathf.Min(roomInfo.GetVerticalEnd(), nextRoomInfo.GetVerticalEnd()) -
  638. Mathf.Max(roomInfo.GetVerticalStart(), nextRoomInfo.GetVerticalStart());
  639. //这种情况下y轴有重叠
  640. if (overlapY >= 6)
  641. {
  642. //找到重叠区域
  643. var rangeList = FindPassage(roomInfo, nextRoomInfo,
  644. roomInfo.GetHorizontalStart() < nextRoomInfo.GetHorizontalStart() ? DoorDirection.E : DoorDirection.W);
  645.  
  646. while (rangeList.Count > 0)
  647. {
  648. //找到重叠区域
  649. var range = Random.RandomChooseAndRemove(rangeList);
  650. var y = Random.RandomRangeInt(range.X, range.Y) + 3;
  651. if (roomInfo.GetHorizontalStart() < nextRoomInfo.GetHorizontalStart()) //room在左, nextRoom在右
  652. {
  653. roomDoor.Direction = DoorDirection.E;
  654. nextRoomDoor.Direction = DoorDirection.W;
  655. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorEnd(), y);
  656. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart(), y);
  657. }
  658. else //room在右, nextRoom在左
  659. {
  660. roomDoor.Direction = DoorDirection.W;
  661. nextRoomDoor.Direction = DoorDirection.E;
  662. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart(), y);
  663. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorEnd(), y);
  664. }
  665.  
  666. //判断门之间的通道是否有物体碰到
  667. if (!AddCorridorToGridRange(roomDoor, nextRoomDoor))
  668. {
  669. //此门不能连通
  670. continue;
  671. }
  672.  
  673. //没有撞到物体
  674. roomInfo.Doors.Add(roomDoor);
  675. nextRoomInfo.Doors.Add(nextRoomDoor);
  676. return true;
  677. }
  678. }
  679.  
  680. return false;
  681. }
  682.  
  683. /// <summary>
  684. /// 尝试寻找包含拐角的两个房间的连通的门, 返回是否找到
  685. /// </summary>
  686. private bool TryConnectCrossDoor(RoomInfo roomInfo, RoomDoorInfo roomDoor, RoomInfo nextRoomInfo, RoomDoorInfo nextRoomDoor)
  687. {
  688. //焦点
  689. Vector2I cross = default;
  690.  
  691. if (roomInfo.GetHorizontalStart() > nextRoomInfo.GetHorizontalStart())
  692. {
  693. if (roomInfo.GetVerticalStart() > nextRoomInfo.GetVerticalStart())
  694. {
  695. if (Random.RandomBoolean()) //↑ //→
  696. {
  697. if (!TryConnect_NE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  698. !TryConnect_WS_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  699. {
  700. return false;
  701. }
  702. }
  703. else //← //↓
  704. {
  705. if (!TryConnect_WS_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  706. !TryConnect_NE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  707. {
  708. return false;
  709. }
  710. }
  711. }
  712. else
  713. {
  714. if (Random.RandomBoolean()) //↓ //→
  715. {
  716. if (!TryConnect_SE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  717. !TryConnect_WN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  718. {
  719. return false;
  720. }
  721. }
  722. else //← //↑
  723. {
  724. if (!TryConnect_WN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  725. !TryConnect_SE_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  726. {
  727. return false;
  728. }
  729. }
  730. }
  731. }
  732. else
  733. {
  734. if (roomInfo.GetVerticalStart() > nextRoomInfo.GetVerticalStart()) //→ //↓
  735. {
  736. if (Random.RandomBoolean())
  737. {
  738. if (!TryConnect_ES_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  739. !TryConnect_NW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  740. {
  741. return false;
  742. }
  743. }
  744. else //↑ //←
  745. {
  746. if (!TryConnect_NW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  747. !TryConnect_ES_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  748. {
  749. return false;
  750. }
  751. }
  752. }
  753. else
  754. {
  755. if (Random.RandomBoolean()) //→ //↑
  756. {
  757. if (!TryConnect_EN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  758. !TryConnect_SW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  759. {
  760. return false;
  761. }
  762. }
  763. else //↓ //←
  764. {
  765. if (!TryConnect_SW_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross) &&
  766. !TryConnect_EN_Door(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref cross))
  767. {
  768. return false;
  769. }
  770. }
  771. }
  772. }
  773.  
  774. //判断门之间的通道是否有物体碰到
  775. if (!AddCorridorToGridRange(roomDoor, nextRoomDoor, cross))
  776. {
  777. //此门不能连通
  778. return false;
  779. }
  780.  
  781. roomDoor.HasCross = true;
  782. roomDoor.Cross = cross;
  783. nextRoomDoor.HasCross = true;
  784. nextRoomDoor.Cross = cross;
  785.  
  786. roomInfo.Doors.Add(roomDoor);
  787. nextRoomInfo.Doors.Add(nextRoomDoor);
  788. return true;
  789. }
  790.  
  791. private bool FindCrossPassage(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor,ref int offset1, ref int offset2)
  792. {
  793. var room1 = roomInfo.RoomSplit.RoomInfo;
  794. var room2 = nextRoomInfo.RoomSplit.RoomInfo;
  795. int? temp1 = null;
  796. int? temp2 = null;
  797.  
  798. foreach (var areaInfo1 in room1.GetCompletionDoorArea())
  799. {
  800. if (areaInfo1.Direction == roomDoor.Direction)
  801. {
  802. FindCrossPassage_Area(areaInfo1, roomInfo, nextRoomInfo, ref temp1);
  803. }
  804. }
  805. if (temp1 == null)
  806. {
  807. return false;
  808. }
  809.  
  810. foreach (var areaInfo2 in room2.GetCompletionDoorArea())
  811. {
  812. if (areaInfo2.Direction == nextRoomDoor.Direction)
  813. {
  814. FindCrossPassage_Area(areaInfo2, nextRoomInfo, roomInfo, ref temp2);
  815. }
  816. }
  817.  
  818. if (temp2 == null)
  819. {
  820. return false;
  821. }
  822. offset1 = temp1.Value;
  823. offset2 = temp2.Value;
  824. return true;
  825. }
  826.  
  827. private void FindCrossPassage_Area(DoorAreaInfo areaInfo, RoomInfo room1, RoomInfo room2, ref int? areaRange)
  828. {
  829. if (areaInfo.Direction == DoorDirection.N || areaInfo.Direction == DoorDirection.S) //纵向门
  830. {
  831. var num = room1.GetHorizontalStart();
  832. var p1 = num + GetDoorAreaInfoStart(areaInfo) / GameConfig.TileCellSize;
  833. var p2 = num + GetDoorAreaInfoEnd(areaInfo) / GameConfig.TileCellSize;
  834.  
  835. if (room1.Position.X > room2.Position.X)
  836. {
  837. var range = CalcOverlapRange(room2.GetHorizontalEnd() + GameConfig.RoomSpace,
  838. room1.GetHorizontalEnd(), p1, p2);
  839. //交集范围够生成门
  840. if (range.Y - range.X >= GameConfig.CorridorWidth)
  841. {
  842. // var tempRange = new Vector2I(Mathf.Abs(room1.Position.X - (int)range.X),
  843. // Mathf.Abs(room1.Position.X - (int)range.Y) - GameConfig.CorridorWidth);
  844. var rangeValue = Mathf.Abs(room1.Position.X - (int)range.X);
  845.  
  846. if (areaRange == null || rangeValue < areaRange)
  847. {
  848. areaRange = rangeValue;
  849. }
  850. }
  851. }
  852. else
  853. {
  854. var range = CalcOverlapRange(room1.GetHorizontalStart(),
  855. room2.GetHorizontalStart() - + GameConfig.RoomSpace, p1, p2);
  856. //交集范围够生成门
  857. if (range.Y - range.X >= GameConfig.CorridorWidth)
  858. {
  859. // var tempRange = new Vector2I(Mathf.Abs(room1.Position.X - (int)range.X),
  860. // Mathf.Abs(room1.Position.X - (int)range.Y) - GameConfig.CorridorWidth);
  861.  
  862. var rangeValue = Mathf.Abs(room1.Position.X - (int)range.Y) - GameConfig.CorridorWidth;
  863.  
  864. if (areaRange == null || rangeValue > areaRange)
  865. {
  866. areaRange = rangeValue;
  867. }
  868. }
  869. }
  870. }
  871. else //横向门
  872. {
  873. var num = room1.GetVerticalStart();
  874. var p1 = num + GetDoorAreaInfoStart(areaInfo) / GameConfig.TileCellSize;
  875. var p2 = num + GetDoorAreaInfoEnd(areaInfo) / GameConfig.TileCellSize;
  876.  
  877. if (room1.Position.Y > room2.Position.Y)
  878. {
  879. var range = CalcOverlapRange(room2.GetVerticalEnd() + GameConfig.RoomSpace,
  880. room1.GetVerticalEnd(), p1, p2);
  881. //交集范围够生成门
  882. if (range.Y - range.X >= GameConfig.CorridorWidth)
  883. {
  884. // var tempRange = new Vector2I(Mathf.Abs(room1.Position.Y - (int)range.X),
  885. // Mathf.Abs(room1.Position.Y - (int)range.Y) - GameConfig.CorridorWidth);
  886.  
  887. var rangeValue = Mathf.Abs(room1.Position.Y - (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.GetVerticalStart(),
  898. room2.GetVerticalStart() - GameConfig.RoomSpace, p1, p2);
  899. //交集范围够生成门
  900. if (range.Y - range.X >= GameConfig.CorridorWidth)
  901. {
  902. // var tempRange = new Vector2I(Mathf.Abs(room1.Position.Y - (int)range.X),
  903. // Mathf.Abs(room1.Position.Y - (int)range.Y) - GameConfig.CorridorWidth);
  904. var rangeValue = Mathf.Abs(room1.Position.Y - (int)range.Y) - GameConfig.CorridorWidth;
  905.  
  906. if (areaRange == null || rangeValue > areaRange)
  907. {
  908. areaRange = rangeValue;
  909. }
  910. }
  911. }
  912. }
  913. }
  914.  
  915. private bool TryConnect_NE_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  916. {
  917. var offset1 = 0;
  918. var offset2 = 0;
  919. roomDoor.Direction = DoorDirection.N; //↑
  920. nextRoomDoor.Direction = DoorDirection.E; //→
  921.  
  922. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  923. {
  924. return false;
  925. }
  926.  
  927. offset1 += 1;
  928. offset2 += 1;
  929. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart() + offset1, roomInfo.GetVerticalDoorStart());
  930. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorEnd(),
  931. nextRoomInfo.GetVerticalDoorStart() + offset2);
  932. cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  933. return true;
  934. }
  935.  
  936. private bool TryConnect_WS_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  937. {
  938. //ok
  939. var offset1 = 0;
  940. var offset2 = 0;
  941. roomDoor.Direction = DoorDirection.W; //←
  942. nextRoomDoor.Direction = DoorDirection.S; //↓
  943. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  944. {
  945. return false;
  946. }
  947.  
  948. offset1 += 1;
  949. offset2 += 1;
  950. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart(), roomInfo.GetVerticalDoorStart() + offset1);
  951. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart() + offset2, nextRoomInfo.GetVerticalDoorEnd());
  952. cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  953. return true;
  954. }
  955.  
  956. private bool TryConnect_SE_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  957. {
  958. var offset1 = 0;
  959. var offset2 = 0;
  960. roomDoor.Direction = DoorDirection.S; //↓
  961. nextRoomDoor.Direction = DoorDirection.E; //→
  962. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  963. {
  964. return false;
  965. }
  966.  
  967. offset1 += 1;
  968. offset2 += 1;
  969. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart() + offset1, roomInfo.GetVerticalDoorEnd());
  970. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorEnd(),
  971. nextRoomInfo.GetVerticalDoorStart() + offset2);
  972. cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  973. return true;
  974. }
  975.  
  976. private bool TryConnect_WN_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  977. {
  978. var offset1 = 0;
  979. var offset2 = 0;
  980. roomDoor.Direction = DoorDirection.W; //←
  981. nextRoomDoor.Direction = DoorDirection.N; //↑
  982. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  983. {
  984. return false;
  985. }
  986.  
  987. offset1 += 1;
  988. offset2 += 1;
  989. roomDoor.OriginPosition =
  990. new Vector2I(roomInfo.GetHorizontalDoorStart(), roomInfo.GetVerticalDoorStart() + offset1); //
  991. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart() + offset2,
  992. nextRoomInfo.GetVerticalDoorStart());
  993. cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  994. return true;
  995. }
  996. private bool TryConnect_ES_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  997. {
  998. var offset1 = 0;
  999. var offset2 = 0;
  1000. roomDoor.Direction = DoorDirection.E; //→
  1001. nextRoomDoor.Direction = DoorDirection.S; //↓
  1002.  
  1003. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1004. {
  1005. return false;
  1006. }
  1007.  
  1008. offset1 += 1;
  1009. offset2 += 1;
  1010. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorEnd(), roomInfo.GetVerticalDoorStart() + offset1);
  1011. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart() + offset2,
  1012. nextRoomInfo.GetVerticalDoorEnd());
  1013. cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  1014. return true;
  1015. }
  1016. private bool TryConnect_NW_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1017. {
  1018. var offset1 = 0;
  1019. var offset2 = 0;
  1020. roomDoor.Direction = DoorDirection.N; //↑
  1021. nextRoomDoor.Direction = DoorDirection.W; //←
  1022.  
  1023. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1024. {
  1025. return false;
  1026. }
  1027.  
  1028. offset1 += 1;
  1029. offset2 += 1;
  1030. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart() + offset1, roomInfo.GetVerticalDoorStart());
  1031. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart(),
  1032. nextRoomInfo.GetVerticalDoorStart() + offset2);
  1033. cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  1034. return true;
  1035. }
  1036. private bool TryConnect_EN_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1037. {
  1038. var offset1 = 0;
  1039. var offset2 = 0;
  1040. roomDoor.Direction = DoorDirection.E; //→
  1041. nextRoomDoor.Direction = DoorDirection.N; //↑
  1042.  
  1043. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1044. {
  1045. return false;
  1046. }
  1047. offset1 += 1;
  1048. offset2 += 2;
  1049. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorEnd(),
  1050. roomInfo.GetVerticalDoorStart() + offset1);
  1051. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalStart() + offset2, nextRoomInfo.GetVerticalDoorStart());
  1052. cross = new Vector2I(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  1053. return true;
  1054. }
  1055.  
  1056. private bool TryConnect_SW_Door(RoomInfo roomInfo, RoomInfo nextRoomInfo, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2I cross)
  1057. {
  1058. var offset1 = 0;
  1059. var offset2 = 0;
  1060. roomDoor.Direction = DoorDirection.S; //↓
  1061. nextRoomDoor.Direction = DoorDirection.W; //←
  1062.  
  1063. if (!FindCrossPassage(roomInfo, nextRoomInfo, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  1064. {
  1065. return false;
  1066. }
  1067.  
  1068. offset1 += 1;
  1069. offset2 += 1;
  1070. roomDoor.OriginPosition = new Vector2I(roomInfo.GetHorizontalDoorStart() + offset1,
  1071. roomInfo.GetVerticalDoorEnd());
  1072. nextRoomDoor.OriginPosition = new Vector2I(nextRoomInfo.GetHorizontalDoorStart(), nextRoomInfo.GetVerticalDoorStart() + offset2);
  1073. cross = new Vector2I(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  1074. return true;
  1075. }
  1076.  
  1077. /// <summary>
  1078. /// 查找房间的连接通道, 函数返回是否找到对应的门, 通过 result 返回 x/y 轴坐标
  1079. /// </summary>
  1080. /// <param name="roomInfo">第一个房间</param>
  1081. /// <param name="nextRoomInfo">第二个房间</param>
  1082. /// <param name="direction">第一个房间连接方向</param>
  1083. private List<Vector2I> FindPassage(RoomInfo roomInfo, RoomInfo nextRoomInfo, DoorDirection direction)
  1084. {
  1085. var room1 = roomInfo.RoomSplit.RoomInfo;
  1086. var room2 = nextRoomInfo.RoomSplit.RoomInfo;
  1087. //用于存储符合生成条件的区域
  1088. var rangeList = new List<Vector2I>();
  1089. foreach (var doorAreaInfo1 in room1.GetCompletionDoorArea())
  1090. {
  1091. if (doorAreaInfo1.Direction == direction)
  1092. {
  1093. //第二个门的方向
  1094. var direction2 = GetReverseDirection(direction);
  1095. foreach (var doorAreaInfo2 in room2.GetCompletionDoorArea())
  1096. {
  1097. if (doorAreaInfo2.Direction == direction2)
  1098. {
  1099. Vector2 range;
  1100. if (direction == DoorDirection.E || direction == DoorDirection.W) //第二个门向← 或者 第二个门向→
  1101. {
  1102. range = CalcOverlapRange(
  1103. roomInfo.GetVerticalStart() * GameConfig.TileCellSize + GetDoorAreaInfoStart(doorAreaInfo1), roomInfo.GetVerticalStart() * GameConfig.TileCellSize + GetDoorAreaInfoEnd(doorAreaInfo1),
  1104. nextRoomInfo.GetVerticalStart() * GameConfig.TileCellSize + GetDoorAreaInfoStart(doorAreaInfo2), nextRoomInfo.GetVerticalStart() * GameConfig.TileCellSize + GetDoorAreaInfoEnd(doorAreaInfo2)
  1105. );
  1106. }
  1107. else //第二个门向↑ 或者 第二个门向↓
  1108. {
  1109. range = CalcOverlapRange(
  1110. roomInfo.GetHorizontalStart() * GameConfig.TileCellSize + GetDoorAreaInfoStart(doorAreaInfo1), roomInfo.GetHorizontalStart() * GameConfig.TileCellSize + GetDoorAreaInfoEnd(doorAreaInfo1),
  1111. nextRoomInfo.GetHorizontalStart() * GameConfig.TileCellSize + GetDoorAreaInfoStart(doorAreaInfo2), nextRoomInfo.GetHorizontalStart() * GameConfig.TileCellSize + GetDoorAreaInfoEnd(doorAreaInfo2)
  1112. );
  1113. }
  1114. //交集范围够生成门
  1115. if (range.Y - range.X >= GameConfig.CorridorWidth * GameConfig.TileCellSize)
  1116. {
  1117. rangeList.Add(new Vector2I((int)(range.X / GameConfig.TileCellSize), (int)(range.Y / GameConfig.TileCellSize) - GameConfig.CorridorWidth));
  1118. }
  1119. }
  1120. }
  1121. }
  1122. }
  1123. return rangeList;
  1124. }
  1125. /// <summary>
  1126. /// 用于计算重叠区域坐标, 可以理解为一维轴上4个点的中间两个点, 返回的x为起始点, y为结束点
  1127. /// </summary>
  1128. private Vector2 CalcOverlapRange(float start1, float end1, float start2, float end2)
  1129. {
  1130. return new Vector2(Mathf.Max(start1, start2), Mathf.Min(end1, end2));
  1131. }
  1132.  
  1133. /// <summary>
  1134. /// 返回 p1 - p2 是否在 start - end 范围内
  1135. /// </summary>
  1136. private bool IsInRange(float start, float end, float p1, float p2)
  1137. {
  1138. return p1 >= start && p2 <= end;
  1139. }
  1140. //返回指定方向的反方向
  1141. //0上, 1右, 2下, 3左
  1142. private int GetReverseDirection(int direction)
  1143. {
  1144. switch (direction)
  1145. {
  1146. case 0: return 2;
  1147. case 1: return 3;
  1148. case 2: return 0;
  1149. case 3: return 1;
  1150. }
  1151.  
  1152. return 2;
  1153. }
  1154. //返回参数方向的反方向
  1155. private DoorDirection GetReverseDirection(DoorDirection direction)
  1156. {
  1157. switch (direction)
  1158. {
  1159. case DoorDirection.E:
  1160. return DoorDirection.W;
  1161. case DoorDirection.W:
  1162. return DoorDirection.E;
  1163. case DoorDirection.S:
  1164. return DoorDirection.N;
  1165. case DoorDirection.N:
  1166. return DoorDirection.S;
  1167. }
  1168.  
  1169. return DoorDirection.S;
  1170. }
  1171.  
  1172. //将两个门间的过道占用数据存入RoomGrid
  1173. private bool AddCorridorToGridRange(RoomDoorInfo door1, RoomDoorInfo door2)
  1174. {
  1175. var point1 = door1.OriginPosition;
  1176. var point2 = door2.OriginPosition;
  1177. var pos = new Vector2I(Mathf.Min(point1.X, point2.X), Mathf.Min(point1.Y, point2.Y));
  1178. var size = new Vector2I(
  1179. point1.X == point2.X ? GameConfig.CorridorWidth : Mathf.Abs(point1.X - point2.X),
  1180. point1.Y == point2.Y ? GameConfig.CorridorWidth : Mathf.Abs(point1.Y - point2.Y)
  1181. );
  1182.  
  1183. Vector2I collPos;
  1184. Vector2I collSize;
  1185. if (point1.X == point2.X) //纵向加宽, 防止贴到其它墙
  1186. {
  1187. pos.Y += 1;
  1188. size.Y -= 3;
  1189. collPos = new Vector2I(pos.X - GameConfig.RoomSpace, pos.Y);
  1190. collSize = new Vector2I(size.X + GameConfig.RoomSpace * 2, size.Y);
  1191. }
  1192. else //横向加宽, 防止贴到其它墙
  1193. {
  1194. pos.X += 1;
  1195. size.X -= 2;
  1196. collPos = new Vector2I(pos.X, pos.Y - GameConfig.RoomSpace);
  1197. collSize = new Vector2I(size.X, size.Y + GameConfig.RoomSpace * 2);
  1198. }
  1199.  
  1200. if (_roomGrid.RectCollision(collPos, collSize))
  1201. {
  1202. return false;
  1203. }
  1204.  
  1205. door2.RoomInfo.AisleArea.Add(new Rect2I(pos, size));
  1206. _roomGrid.SetRect(pos, size, true);
  1207. return true;
  1208. }
  1209.  
  1210. //将两个门间的过道占用数据存入RoomGrid, 该重载加入拐角点
  1211. private bool AddCorridorToGridRange(RoomDoorInfo door1, RoomDoorInfo door2, Vector2I cross)
  1212. {
  1213. if (_roomGrid.RectCollision(cross - new Vector2I(1, 2), new Vector2I(GameConfig.CorridorWidth + 2, GameConfig.CorridorWidth + 3)))
  1214. {
  1215. return false;
  1216. }
  1217. var point1 = door1.OriginPosition;
  1218. var point2 = door2.OriginPosition;
  1219. var pos1 = new Vector2I(Mathf.Min(point1.X, cross.X), Mathf.Min(point1.Y, cross.Y));
  1220. var size1 = new Vector2I(
  1221. point1.X == cross.X ? GameConfig.CorridorWidth : Mathf.Abs(point1.X - cross.X),
  1222. point1.Y == cross.Y ? GameConfig.CorridorWidth : Mathf.Abs(point1.Y - cross.Y)
  1223. );
  1224. var pos2 = new Vector2I(Mathf.Min(point2.X, cross.X), Mathf.Min(point2.Y, cross.Y));
  1225. var size2 = new Vector2I(
  1226. point2.X == cross.X ? GameConfig.CorridorWidth : Mathf.Abs(point2.X - cross.X),
  1227. point2.Y == cross.Y ? GameConfig.CorridorWidth : Mathf.Abs(point2.Y - cross.Y)
  1228. );
  1229.  
  1230. Vector2I collPos1;
  1231. Vector2I collSize1;
  1232. if (point1.X == cross.X) //纵向加宽, 防止贴到其它墙
  1233. {
  1234. if (door1.Direction == DoorDirection.N)
  1235. {
  1236. size1.Y -= 2;
  1237. }
  1238. else
  1239. {
  1240. pos1.Y += 1;
  1241. size1.Y -= 1;
  1242. }
  1243. collPos1 = new Vector2I(pos1.X - GameConfig.RoomSpace, pos1.Y);
  1244. collSize1 = new Vector2I(size1.X + GameConfig.RoomSpace * 2, size1.Y);
  1245. }
  1246. else //横向加宽, 防止贴到其它墙
  1247. {
  1248. if (door1.Direction == DoorDirection.E)
  1249. {
  1250. pos1.X += 1;
  1251. size1.X -= 1;
  1252. }
  1253. else
  1254. {
  1255. size1.X -= 1;
  1256. }
  1257. collPos1 = new Vector2I(pos1.X, pos1.Y - GameConfig.RoomSpace);
  1258. collSize1 = new Vector2I(size1.X, size1.Y + GameConfig.RoomSpace * 2);
  1259. }
  1260.  
  1261. if (_roomGrid.RectCollision(collPos1, collSize1))
  1262. {
  1263. return false;
  1264. }
  1265.  
  1266. Vector2I collPos2;
  1267. Vector2I collSize2;
  1268. if (point2.X == cross.X) //纵向加宽, 防止贴到其它墙
  1269. {
  1270. if (door2.Direction == DoorDirection.N)
  1271. {
  1272. size2.Y -= 2;
  1273. }
  1274. else
  1275. {
  1276. pos2.Y += 1;
  1277. size2.Y -= 1;
  1278. }
  1279. collPos2 = new Vector2I(pos2.X - GameConfig.RoomSpace, pos2.Y);
  1280. collSize2 = new Vector2I(size2.X + GameConfig.RoomSpace * 2, size2.Y);
  1281. }
  1282. else //横向加宽, 防止贴到其它墙
  1283. {
  1284. if (door2.Direction == DoorDirection.E)
  1285. {
  1286. pos2.X += 1;
  1287. size2.X -= 1;
  1288. }
  1289. else
  1290. {
  1291. size2.X -= 1;
  1292. }
  1293. collPos2 = new Vector2I(pos2.X, pos2.Y - GameConfig.RoomSpace);
  1294. collSize2 = new Vector2I(size2.X, size2.Y + GameConfig.RoomSpace * 2);
  1295. }
  1296.  
  1297. if (_roomGrid.RectCollision(collPos2, collSize2))
  1298. {
  1299. return false;
  1300. }
  1301.  
  1302. door2.RoomInfo.AisleArea.Add(new Rect2I(pos1, size1));
  1303. door2.RoomInfo.AisleArea.Add(new Rect2I(pos2, size2));
  1304. _roomGrid.SetRect(pos1, size1, true);
  1305. _roomGrid.SetRect(pos2, size2, true);
  1306. return true;
  1307. }
  1308.  
  1309. private int GetDoorAreaInfoStart(DoorAreaInfo areaInfo)
  1310. {
  1311. return areaInfo.Start;
  1312. }
  1313.  
  1314. private int GetDoorAreaInfoEnd(DoorAreaInfo areaInfo)
  1315. {
  1316. return areaInfo.End;
  1317. }
  1318. }