Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / GenerateDungeon.cs
  1.  
  2. using System;
  3. using System.Collections.Generic;
  4. using Godot;
  5.  
  6. /// <summary>
  7. /// 地牢生成器
  8. /// </summary>
  9. public class GenerateDungeon
  10. {
  11. /// <summary>
  12. /// 过道宽度
  13. /// </summary>
  14. public const int CorridorWidth = 4;
  15.  
  16. /// <summary>
  17. /// tilemap 网格大小
  18. /// </summary>
  19. public const int TileCellSize = 16;
  20. /// <summary>
  21. /// 所有生成的房间, 调用过 Generate() 函数才能获取到值
  22. /// </summary>
  23. public List<RoomInfo> RoomInfos { get; } = new List<RoomInfo>();
  24.  
  25. /// <summary>
  26. /// 起始房间
  27. /// </summary>
  28. public RoomInfo StartRoom { get; private set; }
  29. /// <summary>
  30. /// 生成的房间数量
  31. /// </summary>
  32. private int _maxCount = 15;
  33.  
  34. //用于标记地图上的坐标是否被占用
  35. private Grid<bool> _roomGrid { get; } = new Grid<bool>();
  36. //当前房间数量
  37. private int _count = 0;
  38. //宽高
  39. private int _roomMinWidth = 15;
  40. private int _roomMaxWidth = 35;
  41. private int _roomMinHeight = 15;
  42. private int _roomMaxHeight = 30;
  43.  
  44. //间隔
  45. private int _roomMinInterval = 6;
  46. private int _roomMaxInterval = 10;
  47.  
  48. //房间横轴分散程度
  49. private float _roomHorizontalMinDispersion = 0.7f;
  50. private float _roomHorizontalMaxDispersion = 1.1f;
  51.  
  52. //房间纵轴分散程度
  53. private float _roomVerticalMinDispersion = 0.7f;
  54. private float _roomVerticalMaxDispersion = 1.1f;
  55.  
  56. //区域限制
  57. private bool _enableLimitRange = true;
  58. private int _rangeX = 110;
  59. private int _rangeY = 110;
  60. //找房间失败次数, 过大则会关闭区域限制
  61. private int _maxFailCount = 10;
  62. private int _failCount = 0;
  63.  
  64. private enum GenerateRoomErrorCode
  65. {
  66. NoError,
  67. //房间已满
  68. RoomFull,
  69. //超出区域
  70. OutArea,
  71. //碰到其他房间或过道
  72. HasCollision,
  73. //没有合适的门
  74. NoProperDoor,
  75. }
  76. /// <summary>
  77. /// 生成房间
  78. /// </summary>
  79. public void Generate()
  80. {
  81. if (StartRoom != null) return;
  82.  
  83. //第一个房间
  84. GenerateRoom(null, 0, out var startRoom);
  85. StartRoom = startRoom;
  86. //如果房间数量不够, 就一直生成
  87. while (_count < _maxCount)
  88. {
  89. var room = Utils.RandomChoose(RoomInfos);
  90. var errorCode = GenerateRoom(room, Utils.RandomRangeInt(0, 3), out var nextRoom);
  91. if (errorCode == GenerateRoomErrorCode.NoError)
  92. {
  93. _failCount = 0;
  94. room.Next.Add(nextRoom);
  95. }
  96. else
  97. {
  98. GD.Print("生成第" + (_count + 1) + "个房间失败! 失败原因: " + errorCode);
  99. if (errorCode == GenerateRoomErrorCode.OutArea)
  100. {
  101. _failCount++;
  102. GD.Print("超出区域失败次数: " + _failCount);
  103. if (_failCount >= _maxFailCount)
  104. {
  105. _enableLimitRange = false;
  106. GD.Print("生成房间失败次数过多, 关闭区域限制!");
  107. }
  108. }
  109. }
  110. }
  111. _roomGrid.Clear();
  112. }
  113.  
  114. //生成房间
  115. private GenerateRoomErrorCode GenerateRoom(RoomInfo prevRoomInfo, int direction, out RoomInfo resultRoom)
  116. {
  117. if (_count >= _maxCount)
  118. {
  119. resultRoom = null;
  120. return GenerateRoomErrorCode.RoomFull;
  121. }
  122.  
  123. //随机选择一个房间
  124. var roomSplit = Utils.RandomChoose(GameApplication.Instance.RoomConfig);
  125. var room = new RoomInfo(_count, roomSplit);
  126. //房间大小
  127. room.Size = new Vector2I((int)roomSplit.RoomInfo.Size.X, (int)roomSplit.RoomInfo.Size.Y);
  128.  
  129. if (prevRoomInfo != null) //表示这不是第一个房间, 就得判断当前位置下的房间是否被遮挡
  130. {
  131. //房间间隔
  132. var space = Utils.RandomRangeInt(_roomMinInterval, _roomMaxInterval);
  133. //中心偏移
  134. int offset;
  135. if (direction == 0 || direction == 2)
  136. {
  137. offset = Utils.RandomRangeInt(-(int)(prevRoomInfo.Size.X * _roomVerticalMinDispersion),
  138. (int)(prevRoomInfo.Size.X * _roomVerticalMaxDispersion));
  139. }
  140. else
  141. {
  142. offset = Utils.RandomRangeInt(-(int)(prevRoomInfo.Size.Y * _roomHorizontalMinDispersion),
  143. (int)(prevRoomInfo.Size.Y * _roomHorizontalMaxDispersion));
  144. }
  145.  
  146. //计算房间位置
  147. if (direction == 0) //上
  148. {
  149. room.Position = new Vector2I(prevRoomInfo.Position.X + offset,
  150. prevRoomInfo.Position.Y - room.Size.Y - space);
  151. }
  152. else if (direction == 1) //右
  153. {
  154. room.Position = new Vector2I(prevRoomInfo.Position.X + prevRoomInfo.Size.Y + space,
  155. prevRoomInfo.Position.Y + offset);
  156. }
  157. else if (direction == 2) //下
  158. {
  159. room.Position = new Vector2I(prevRoomInfo.Position.X + offset,
  160. prevRoomInfo.Position.Y + prevRoomInfo.Size.Y + space);
  161. }
  162. else if (direction == 3) //左
  163. {
  164. room.Position = new Vector2I(prevRoomInfo.Position.X - room.Size.X - space,
  165. prevRoomInfo.Position.Y + offset);
  166. }
  167. //是否在限制区域内
  168. if (_enableLimitRange)
  169. {
  170. if (room.GetHorizontalStart() < -_rangeX || room.GetHorizontalEnd() > _rangeX || room.GetVerticalStart() < -_rangeY || room.GetVerticalEnd() > _rangeY)
  171. {
  172. resultRoom = null;
  173. return GenerateRoomErrorCode.OutArea;
  174. }
  175. }
  176.  
  177. //是否碰到其他房间或者过道
  178. if (_roomGrid.RectCollision(room.Position - new Vector2(3, 3), room.Size + new Vector2(6, 6)))
  179. {
  180. resultRoom = null;
  181. return GenerateRoomErrorCode.HasCollision;
  182. }
  183.  
  184. _roomGrid.AddRect(room.Position, room.Size, true);
  185.  
  186. //找门, 与上一个房间是否能连通
  187. if (!ConnectDoor(prevRoomInfo, room))
  188. {
  189. _roomGrid.RemoveRect(room.Position, room.Size);
  190. resultRoom = null;
  191. return GenerateRoomErrorCode.NoProperDoor;
  192. }
  193. }
  194.  
  195. _count++;
  196. RoomInfos.Add(room);
  197. if (prevRoomInfo == null)
  198. {
  199. _roomGrid.AddRect(room.Position, room.Size, true);
  200. }
  201.  
  202. //下一个房间
  203. //0上, 1右, 2下, 3左
  204. var dirList = new List<int>(new[] { 0, 1, 2, 3 });
  205. if (prevRoomInfo != null)
  206. {
  207. dirList.Remove(GetReverseDirection(direction));
  208. }
  209.  
  210. //这条线有一定概率不生成下一个房间
  211. if (Utils.RandomRangeInt(0, 2) != 0)
  212. {
  213. while (dirList.Count > 0)
  214. {
  215. var randDir = Utils.RandomChoose(dirList);
  216. GenerateRoom(room, randDir, out var nextRoom);
  217. if (nextRoom == null)
  218. {
  219. break;
  220. }
  221.  
  222. nextRoom.Prev = room;
  223. room.Next.Add(nextRoom);
  224.  
  225. dirList.Remove(randDir);
  226. }
  227. }
  228.  
  229. resultRoom = room;
  230. return GenerateRoomErrorCode.NoError;
  231. }
  232.  
  233. /// <summary>
  234. /// 找两个房间的门
  235. /// </summary>
  236. private bool ConnectDoor(RoomInfo room, RoomInfo nextRoom)
  237. {
  238. //门描述
  239. var roomDoor = new RoomDoorInfo();
  240. var nextRoomDoor = new RoomDoorInfo();
  241. roomDoor.RoomInfo = room;
  242. nextRoomDoor.RoomInfo = nextRoom;
  243. roomDoor.ConnectRoom = nextRoom;
  244. roomDoor.ConnectDoor = nextRoomDoor;
  245. nextRoomDoor.ConnectRoom = room;
  246. nextRoomDoor.ConnectDoor = roomDoor;
  247.  
  248. //先寻找直通门
  249. if (Utils.RandomBoolean())
  250. {
  251. //直行通道, 优先横轴
  252. if (TryConnectHorizontalDoor(room, roomDoor, nextRoom, nextRoomDoor)
  253. || TryConnectVerticalDoor(room, roomDoor, nextRoom, nextRoomDoor))
  254. {
  255. return true;
  256. }
  257. }
  258. else
  259. {
  260. //直行通道, 优先纵轴
  261. if (TryConnectVerticalDoor(room, roomDoor, nextRoom, nextRoomDoor)
  262. || TryConnectHorizontalDoor(room, roomDoor, nextRoom, nextRoomDoor))
  263. {
  264. return true;
  265. }
  266. }
  267. //包含拐角的通道
  268. return TryConnectCrossDoor(room, roomDoor, nextRoom, nextRoomDoor);
  269. }
  270.  
  271. /// <summary>
  272. /// 尝试寻找横轴方向上两个房间的连通的门, 只查找直线通道, 返回是否找到
  273. /// </summary>
  274. private bool TryConnectHorizontalDoor(RoomInfo room, RoomDoorInfo roomDoor, RoomInfo nextRoom, RoomDoorInfo nextRoomDoor)
  275. {
  276. var overlapX = Mathf.Min(room.GetHorizontalEnd(), nextRoom.GetHorizontalEnd()) -
  277. Mathf.Max(room.GetHorizontalStart(), nextRoom.GetHorizontalStart());
  278. //这种情况下x轴有重叠
  279. if (overlapX >= 6)
  280. {
  281. //找到重叠区域
  282. var rangeList = FindPassage(room, nextRoom,
  283. room.GetVerticalStart() < nextRoom.GetVerticalStart() ? DoorDirection.S : DoorDirection.N);
  284. while (rangeList.Count > 0)
  285. {
  286. //找到重叠区域
  287. var range = Utils.RandomChooseAndRemove(rangeList);
  288. var x = Utils.RandomRangeInt(range.X, range.Y);
  289. if (room.GetVerticalStart() < nextRoom.GetVerticalStart()) //room在上, nextRoom在下
  290. {
  291. roomDoor.Direction = DoorDirection.S;
  292. nextRoomDoor.Direction = DoorDirection.N;
  293. roomDoor.OriginPosition = new Vector2(x, room.GetVerticalEnd());
  294. nextRoomDoor.OriginPosition = new Vector2(x, nextRoom.GetVerticalStart());
  295. }
  296. else //room在下, nextRoom在上
  297. {
  298. roomDoor.Direction = DoorDirection.N;
  299. nextRoomDoor.Direction = DoorDirection.S;
  300. roomDoor.OriginPosition = new Vector2(x, room.GetVerticalStart());
  301. nextRoomDoor.OriginPosition = new Vector2(x, nextRoom.GetVerticalEnd());
  302. }
  303.  
  304. //判断门之间的通道是否有物体碰到
  305. if (!AddCorridorToGridRange(roomDoor, nextRoomDoor))
  306. {
  307. //此门不能连通
  308. continue;
  309. }
  310.  
  311. //没有撞到物体
  312. room.Doors.Add(roomDoor);
  313. nextRoom.Doors.Add(nextRoomDoor);
  314. return true;
  315. }
  316. }
  317. return false;
  318. }
  319.  
  320. /// <summary>
  321. /// 尝试寻找纵轴方向上两个房间的连通的门, 只查找直线通道, 返回是否找到
  322. /// </summary>
  323. private bool TryConnectVerticalDoor(RoomInfo room, RoomDoorInfo roomDoor, RoomInfo nextRoom, RoomDoorInfo nextRoomDoor)
  324. {
  325. var overlapY = Mathf.Min(room.GetVerticalEnd(), nextRoom.GetVerticalEnd()) -
  326. Mathf.Max(room.GetVerticalStart(), nextRoom.GetVerticalStart());
  327. //这种情况下y轴有重叠
  328. if (overlapY >= 6)
  329. {
  330. //找到重叠区域
  331. var rangeList = FindPassage(room, nextRoom,
  332. room.GetHorizontalStart() < nextRoom.GetHorizontalStart() ? DoorDirection.E : DoorDirection.W);
  333.  
  334. while (rangeList.Count > 0)
  335. {
  336. //找到重叠区域
  337. var range = Utils.RandomChooseAndRemove(rangeList);
  338. var y = Utils.RandomRangeInt(range.X, range.Y);
  339. if (room.GetHorizontalStart() < nextRoom.GetHorizontalStart()) //room在左, nextRoom在右
  340. {
  341. roomDoor.Direction = DoorDirection.E;
  342. nextRoomDoor.Direction = DoorDirection.W;
  343. roomDoor.OriginPosition = new Vector2(room.GetHorizontalEnd(), y);
  344. nextRoomDoor.OriginPosition = new Vector2(nextRoom.GetHorizontalStart(), y);
  345. }
  346. else //room在右, nextRoom在左
  347. {
  348. roomDoor.Direction = DoorDirection.W;
  349. nextRoomDoor.Direction = DoorDirection.E;
  350. roomDoor.OriginPosition = new Vector2(room.GetHorizontalStart(), y);
  351. nextRoomDoor.OriginPosition = new Vector2(nextRoom.GetHorizontalEnd(), y);
  352. }
  353.  
  354. //判断门之间的通道是否有物体碰到
  355. if (!AddCorridorToGridRange(roomDoor, nextRoomDoor))
  356. {
  357. //此门不能连通
  358. continue;
  359. }
  360.  
  361. //没有撞到物体
  362. room.Doors.Add(roomDoor);
  363. nextRoom.Doors.Add(nextRoomDoor);
  364. return true;
  365. }
  366. }
  367.  
  368. return false;
  369. }
  370.  
  371. /// <summary>
  372. /// 尝试寻找包含拐角的两个房间的连通的门, 返回是否找到
  373. /// </summary>
  374. private bool TryConnectCrossDoor(RoomInfo room, RoomDoorInfo roomDoor, RoomInfo nextRoom, RoomDoorInfo nextRoomDoor)
  375. {
  376. //焦点
  377. Vector2 cross = default;
  378.  
  379. if (room.GetHorizontalStart() > nextRoom.GetHorizontalStart())
  380. {
  381. if (room.GetVerticalStart() > nextRoom.GetVerticalStart())
  382. {
  383. if (Utils.RandomBoolean()) //↑ //→
  384. {
  385. if (!TryConnect_NE_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross) &&
  386. !TryConnect_WS_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross))
  387. {
  388. return false;
  389. }
  390. }
  391. else //← //↓
  392. {
  393. if (!TryConnect_WS_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross) &&
  394. !TryConnect_NE_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross))
  395. {
  396. return false;
  397. }
  398. }
  399. }
  400. else
  401. {
  402. if (Utils.RandomBoolean()) //↓ //→
  403. {
  404. if (!TryConnect_SE_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross) &&
  405. !TryConnect_WN_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross))
  406. {
  407. return false;
  408. }
  409. }
  410. else //← //↑
  411. {
  412. if (!TryConnect_WN_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross) &&
  413. !TryConnect_SE_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross))
  414. {
  415. return false;
  416. }
  417. }
  418. }
  419. }
  420. else
  421. {
  422. if (room.GetVerticalStart() > nextRoom.GetVerticalStart()) //→ //↓
  423. {
  424. if (Utils.RandomBoolean())
  425. {
  426. if (!TryConnect_ES_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross) &&
  427. !TryConnect_NW_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross))
  428. {
  429. return false;
  430. }
  431. }
  432. else //↑ //←
  433. {
  434. if (!TryConnect_NW_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross) &&
  435. !TryConnect_ES_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross))
  436. {
  437. return false;
  438. }
  439. }
  440. }
  441. else
  442. {
  443. if (Utils.RandomBoolean()) //→ //↑
  444. {
  445. if (!TryConnect_EN_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross) &&
  446. !TryConnect_SW_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross))
  447. {
  448. return false;
  449. }
  450. }
  451. else //↓ //←
  452. {
  453. if (!TryConnect_SW_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross) &&
  454. !TryConnect_EN_Door(room, nextRoom, roomDoor, nextRoomDoor, ref cross))
  455. {
  456. return false;
  457. }
  458. }
  459. }
  460. }
  461.  
  462. //判断门之间的通道是否有物体碰到
  463. if (!AddCorridorToGridRange(roomDoor, nextRoomDoor, cross))
  464. {
  465. //此门不能连通
  466. return false;
  467. }
  468.  
  469. roomDoor.HasCross = true;
  470. roomDoor.Cross = cross;
  471. nextRoomDoor.HasCross = true;
  472. nextRoomDoor.Cross = cross;
  473.  
  474. room.Doors.Add(roomDoor);
  475. nextRoom.Doors.Add(nextRoomDoor);
  476. return true;
  477. }
  478.  
  479. private bool FindCrossPassage(RoomInfo room, RoomInfo nextRoom, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor,ref int offset1, ref int offset2)
  480. {
  481. var room1 = room.RoomSplit.RoomInfo;
  482. var room2 = nextRoom.RoomSplit.RoomInfo;
  483. Vector2I? temp1 = null;
  484. Vector2I? temp2 = null;
  485.  
  486. foreach (var areaInfo1 in room1.DoorAreaInfos)
  487. {
  488. if (areaInfo1.Direction == roomDoor.Direction)
  489. {
  490. FindCrossPassage_Area(areaInfo1, room, nextRoom, ref temp1);
  491. }
  492. }
  493.  
  494. foreach (var areaInfo2 in room2.DoorAreaInfos)
  495. {
  496. if (areaInfo2.Direction == nextRoomDoor.Direction)
  497. {
  498. FindCrossPassage_Area(areaInfo2, nextRoom, room, ref temp2);
  499. }
  500. }
  501.  
  502. if (temp1 != null && temp2 != null)
  503. {
  504. offset1 = Utils.RandomRangeInt(temp1.Value.X, temp1.Value.Y);
  505. offset2 = Utils.RandomRangeInt(temp2.Value.X, temp2.Value.Y);
  506. return true;
  507. }
  508.  
  509. return false;
  510. }
  511.  
  512. private void FindCrossPassage_Area(DoorAreaInfo areaInfo, RoomInfo room1, RoomInfo room2, ref Vector2I? areaRange)
  513. {
  514. if (areaInfo.Direction == DoorDirection.N || areaInfo.Direction == DoorDirection.S) //纵向门
  515. {
  516. var num = room1.GetHorizontalStart();
  517. var p1 = num + areaInfo.Start / TileCellSize;
  518. var p2 = num + areaInfo.End / TileCellSize;
  519.  
  520. if (room1.Position.X > room2.Position.X)
  521. {
  522. var range = CalcOverlapRange(room2.GetHorizontalEnd(),
  523. room1.GetHorizontalEnd(), p1, p2);
  524. //交集范围够生成门
  525. if (range.Y - range.X >= CorridorWidth)
  526. {
  527. var tempRange = new Vector2I(Mathf.Abs(room1.Position.X - (int)range.X),
  528. Mathf.Abs(room1.Position.X - (int)range.Y) - CorridorWidth);
  529. if (areaRange == null || tempRange.X < areaRange.Value.X)
  530. {
  531. areaRange = tempRange;
  532. }
  533. }
  534. }
  535. else
  536. {
  537. var range = CalcOverlapRange(room1.GetHorizontalStart(),
  538. room2.GetHorizontalStart(), p1, p2);
  539. //交集范围够生成门
  540. if (range.Y - range.X >= CorridorWidth)
  541. {
  542. var tempRange = new Vector2I(Mathf.Abs(room1.Position.X - (int)range.X),
  543. Mathf.Abs(room1.Position.X - (int)range.Y) - CorridorWidth);
  544. if (areaRange == null || tempRange.Y > areaRange.Value.Y)
  545. {
  546. areaRange = tempRange;
  547. }
  548. }
  549. }
  550. }
  551. else //横向门
  552. {
  553. var num = room1.GetVerticalStart();
  554. var p1 = num + areaInfo.Start / TileCellSize;
  555. var p2 = num + areaInfo.End / TileCellSize;
  556.  
  557. if (room1.Position.Y > room2.Position.Y)
  558. {
  559. var range = CalcOverlapRange(room2.GetVerticalEnd(),
  560. room1.GetVerticalEnd(), p1, p2);
  561. //交集范围够生成门
  562. if (range.Y - range.X >= CorridorWidth)
  563. {
  564. var tempRange = new Vector2I(Mathf.Abs(room1.Position.Y - (int)range.X),
  565. Mathf.Abs(room1.Position.Y - (int)range.Y) - CorridorWidth);
  566. if (areaRange == null || tempRange.X < areaRange.Value.X)
  567. {
  568. areaRange = tempRange;
  569. }
  570. }
  571. }
  572. else
  573. {
  574. var range = CalcOverlapRange(room1.GetVerticalStart(),
  575. room2.GetVerticalStart(), p1, p2);
  576. //交集范围够生成门
  577. if (range.Y - range.X >= CorridorWidth)
  578. {
  579. var tempRange = new Vector2I(Mathf.Abs(room1.Position.Y - (int)range.X),
  580. Mathf.Abs(room1.Position.Y - (int)range.Y) - CorridorWidth);
  581. if (areaRange == null || tempRange.Y > areaRange.Value.Y)
  582. {
  583. areaRange = tempRange;
  584. }
  585. }
  586. }
  587. }
  588. }
  589.  
  590. private bool TryConnect_NE_Door(RoomInfo room, RoomInfo nextRoom, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2 cross)
  591. {
  592. var offset1 = 0;
  593. var offset2 = 0;
  594. roomDoor.Direction = DoorDirection.N; //↑
  595. nextRoomDoor.Direction = DoorDirection.E; //→
  596.  
  597. if (!FindCrossPassage(room, nextRoom, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  598. {
  599. return false;
  600. }
  601. roomDoor.OriginPosition = new Vector2(room.GetHorizontalStart() + offset1, room.GetVerticalStart());
  602. nextRoomDoor.OriginPosition = new Vector2(nextRoom.GetHorizontalEnd(),
  603. nextRoom.GetVerticalStart() + offset2);
  604. cross = new Vector2(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  605. return true;
  606. }
  607.  
  608. private bool TryConnect_WS_Door(RoomInfo room, RoomInfo nextRoom, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2 cross)
  609. {
  610. //ok
  611. var offset1 = 0;
  612. var offset2 = 0;
  613. roomDoor.Direction = DoorDirection.W; //←
  614. nextRoomDoor.Direction = DoorDirection.S; //↓
  615. if (!FindCrossPassage(room, nextRoom, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  616. {
  617. return false;
  618. }
  619. roomDoor.OriginPosition = new Vector2(room.GetHorizontalStart(), room.GetVerticalStart() + offset1);
  620. nextRoomDoor.OriginPosition = new Vector2(nextRoom.GetHorizontalStart() + offset2, nextRoom.GetVerticalEnd());
  621. cross = new Vector2(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  622. return true;
  623. }
  624.  
  625. private bool TryConnect_SE_Door(RoomInfo room, RoomInfo nextRoom, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2 cross)
  626. {
  627. var offset1 = 0;
  628. var offset2 = 0;
  629. roomDoor.Direction = DoorDirection.S; //↓
  630. nextRoomDoor.Direction = DoorDirection.E; //→
  631. if (!FindCrossPassage(room, nextRoom, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  632. {
  633. return false;
  634. }
  635.  
  636. roomDoor.OriginPosition = new Vector2(room.GetHorizontalStart() + offset1, room.GetVerticalEnd());
  637. nextRoomDoor.OriginPosition = new Vector2(nextRoom.GetHorizontalEnd(),
  638. nextRoom.GetVerticalStart() + offset2);
  639. cross = new Vector2(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  640. return true;
  641. }
  642.  
  643. private bool TryConnect_WN_Door(RoomInfo room, RoomInfo nextRoom, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2 cross)
  644. {
  645. var offset1 = 0;
  646. var offset2 = 0;
  647. roomDoor.Direction = DoorDirection.W; //←
  648. nextRoomDoor.Direction = DoorDirection.N; //↑
  649. if (!FindCrossPassage(room, nextRoom, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  650. {
  651. return false;
  652. }
  653.  
  654. roomDoor.OriginPosition =
  655. new Vector2(room.GetHorizontalStart(), room.GetVerticalStart() + offset1); //
  656. nextRoomDoor.OriginPosition = new Vector2(nextRoom.GetHorizontalStart() + offset2,
  657. nextRoom.GetVerticalStart());
  658. cross = new Vector2(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  659. return true;
  660. }
  661. private bool TryConnect_ES_Door(RoomInfo room, RoomInfo nextRoom, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2 cross)
  662. {
  663. var offset1 = 0;
  664. var offset2 = 0;
  665. roomDoor.Direction = DoorDirection.E; //→
  666. nextRoomDoor.Direction = DoorDirection.S; //↓
  667.  
  668. if (!FindCrossPassage(room, nextRoom, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  669. {
  670. return false;
  671. }
  672. roomDoor.OriginPosition = new Vector2(room.GetHorizontalEnd(), room.GetVerticalStart() + offset1);
  673. nextRoomDoor.OriginPosition = new Vector2(nextRoom.GetHorizontalStart() + offset2,
  674. nextRoom.GetVerticalEnd());
  675. cross = new Vector2(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  676. return true;
  677. }
  678. private bool TryConnect_NW_Door(RoomInfo room, RoomInfo nextRoom, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2 cross)
  679. {
  680. var offset1 = 0;
  681. var offset2 = 0;
  682. roomDoor.Direction = DoorDirection.N; //↑
  683. nextRoomDoor.Direction = DoorDirection.W; //←
  684.  
  685. if (!FindCrossPassage(room, nextRoom, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  686. {
  687. return false;
  688. }
  689. roomDoor.OriginPosition = new Vector2(room.GetHorizontalStart() + offset1, room.GetVerticalStart());
  690. nextRoomDoor.OriginPosition = new Vector2(nextRoom.GetHorizontalStart(),
  691. nextRoom.GetVerticalStart() + offset2);
  692. cross = new Vector2(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  693. return true;
  694. }
  695. private bool TryConnect_EN_Door(RoomInfo room, RoomInfo nextRoom, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2 cross)
  696. {
  697. var offset1 = 0;
  698. var offset2 = 0;
  699. roomDoor.Direction = DoorDirection.E; //→
  700. nextRoomDoor.Direction = DoorDirection.N; //↑
  701.  
  702. if (!FindCrossPassage(room, nextRoom, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  703. {
  704. return false;
  705. }
  706. roomDoor.OriginPosition = new Vector2(room.GetHorizontalEnd(),
  707. room.GetVerticalStart() + offset1);
  708. nextRoomDoor.OriginPosition = new Vector2(nextRoom.GetHorizontalStart() + offset2, nextRoom.GetVerticalStart());
  709. cross = new Vector2(nextRoomDoor.OriginPosition.X, roomDoor.OriginPosition.Y);
  710. return true;
  711. }
  712.  
  713. private bool TryConnect_SW_Door(RoomInfo room, RoomInfo nextRoom, RoomDoorInfo roomDoor, RoomDoorInfo nextRoomDoor, ref Vector2 cross)
  714. {
  715. var offset1 = 0;
  716. var offset2 = 0;
  717. roomDoor.Direction = DoorDirection.S; //↓
  718. nextRoomDoor.Direction = DoorDirection.W; //←
  719.  
  720. if (!FindCrossPassage(room, nextRoom, roomDoor, nextRoomDoor, ref offset1, ref offset2))
  721. {
  722. return false;
  723. }
  724. roomDoor.OriginPosition = new Vector2(room.GetHorizontalStart() + offset1,
  725. room.GetVerticalEnd());
  726. nextRoomDoor.OriginPosition = new Vector2(nextRoom.GetHorizontalStart(), nextRoom.GetVerticalStart() + offset2);
  727. cross = new Vector2(roomDoor.OriginPosition.X, nextRoomDoor.OriginPosition.Y);
  728. return true;
  729. }
  730.  
  731. /// <summary>
  732. /// 查找房间的连接通道, 函数返回是否找到对应的门, 通过 result 返回 x/y 轴坐标
  733. /// </summary>
  734. /// <param name="room">第一个房间</param>
  735. /// <param name="nextRoom">第二个房间</param>
  736. /// <param name="direction">第一个房间连接方向</param>
  737. private List<Vector2I> FindPassage(RoomInfo room, RoomInfo nextRoom, DoorDirection direction)
  738. {
  739. var room1 = room.RoomSplit.RoomInfo;
  740. var room2 = nextRoom.RoomSplit.RoomInfo;
  741. //用于存储符合生成条件的区域
  742. var rangeList = new List<Vector2I>();
  743. foreach (var doorAreaInfo1 in room1.DoorAreaInfos)
  744. {
  745. if (doorAreaInfo1.Direction == direction)
  746. {
  747. //第二个门的方向
  748. var direction2 = GetReverseDirection(direction);
  749. foreach (var doorAreaInfo2 in room2.DoorAreaInfos)
  750. {
  751. if (doorAreaInfo2.Direction == direction2)
  752. {
  753. Vector2 range;
  754. if (direction == DoorDirection.E || direction == DoorDirection.W) //第二个门向← 或者 第二个门向→
  755. {
  756. range = CalcOverlapRange(
  757. room.GetVerticalStart() * TileCellSize + doorAreaInfo1.Start, room.GetVerticalStart() * TileCellSize + doorAreaInfo1.End,
  758. nextRoom.GetVerticalStart() * TileCellSize + doorAreaInfo2.Start, nextRoom.GetVerticalStart() * TileCellSize + doorAreaInfo2.End
  759. );
  760. }
  761. else //第二个门向↑ 或者 第二个门向↓
  762. {
  763. range = CalcOverlapRange(
  764. room.GetHorizontalStart() * TileCellSize + doorAreaInfo1.Start, room.GetHorizontalStart() * TileCellSize + doorAreaInfo1.End,
  765. nextRoom.GetHorizontalStart() * TileCellSize + doorAreaInfo2.Start, nextRoom.GetHorizontalStart() * TileCellSize + doorAreaInfo2.End
  766. );
  767. }
  768. //交集范围够生成门
  769. if (range.Y - range.X >= CorridorWidth * TileCellSize)
  770. {
  771. rangeList.Add(new Vector2I((int)(range.X / 16), (int)(range.Y / 16) - CorridorWidth));
  772. }
  773. }
  774. }
  775. }
  776. }
  777. return rangeList;
  778. }
  779. /// <summary>
  780. /// 用于计算重叠区域坐标, 可以理解为一维轴上4个点的中间两个点, 返回的x为起始点, y为结束点
  781. /// </summary>
  782. private Vector2 CalcOverlapRange(float start1, float end1, float start2, float end2)
  783. {
  784. return new Vector2(Mathf.Max(start1, start2), Mathf.Min(end1, end2));
  785. }
  786.  
  787. /// <summary>
  788. /// 返回 p1 - p2 是否在 start - end 范围内
  789. /// </summary>
  790. private bool IsInRange(float start, float end, float p1, float p2)
  791. {
  792. return p1 >= start && p2 <= end;
  793. }
  794. //返回指定方向的反方向
  795. //0上, 1右, 2下, 3左
  796. private int GetReverseDirection(int direction)
  797. {
  798. switch (direction)
  799. {
  800. case 0: return 2;
  801. case 1: return 3;
  802. case 2: return 0;
  803. case 3: return 1;
  804. }
  805.  
  806. return 2;
  807. }
  808. //返回参数方向的反方向
  809. private DoorDirection GetReverseDirection(DoorDirection direction)
  810. {
  811. switch (direction)
  812. {
  813. case DoorDirection.E:
  814. return DoorDirection.W;
  815. case DoorDirection.W:
  816. return DoorDirection.E;
  817. case DoorDirection.S:
  818. return DoorDirection.N;
  819. case DoorDirection.N:
  820. return DoorDirection.S;
  821. }
  822.  
  823. return DoorDirection.S;
  824. }
  825.  
  826. //将两个门间的过道占用数据存入RoomGrid
  827. private bool AddCorridorToGridRange(RoomDoorInfo door1, RoomDoorInfo door2)
  828. {
  829. var point1 = door1.OriginPosition;
  830. var point2 = door2.OriginPosition;
  831. var pos = new Vector2(Mathf.Min(point1.X, point2.X), Mathf.Min(point1.Y, point2.Y));
  832. var size = new Vector2(
  833. point1.X == point2.X ? CorridorWidth : Mathf.Abs(point1.X - point2.X),
  834. point1.Y == point2.Y ? CorridorWidth : Mathf.Abs(point1.Y - point2.Y)
  835. );
  836.  
  837. Vector2 collPos;
  838. Vector2 collSize;
  839. if (point1.X == point2.X) //纵向加宽, 防止贴到其它墙
  840. {
  841. collPos = new Vector2(pos.X - 3, pos.Y);
  842. collSize = new Vector2(size.X + 6, size.Y);
  843. }
  844. else //横向加宽, 防止贴到其它墙
  845. {
  846. collPos = new Vector2(pos.X, pos.Y - 3);
  847. collSize = new Vector2(size.X, size.Y + 6);
  848. }
  849.  
  850. if (_roomGrid.RectCollision(collPos, collSize))
  851. {
  852. return false;
  853. }
  854.  
  855. _roomGrid.AddRect(pos, size, true);
  856. return true;
  857. }
  858.  
  859. //将两个门间的过道占用数据存入RoomGrid, 该重载加入拐角点
  860. private bool AddCorridorToGridRange(RoomDoorInfo door1, RoomDoorInfo door2, Vector2 cross)
  861. {
  862. var point1 = door1.OriginPosition;
  863. var point2 = door2.OriginPosition;
  864. var pos1 = new Vector2(Mathf.Min(point1.X, cross.X), Mathf.Min(point1.Y, cross.Y));
  865. var size1 = new Vector2(
  866. point1.X == cross.X ? CorridorWidth : Mathf.Abs(point1.X - cross.X),
  867. point1.Y == cross.Y ? CorridorWidth : Mathf.Abs(point1.Y - cross.Y)
  868. );
  869. var pos2 = new Vector2(Mathf.Min(point2.X, cross.X), Mathf.Min(point2.Y, cross.Y));
  870. var size2 = new Vector2(
  871. point2.X == cross.X ? CorridorWidth : Mathf.Abs(point2.X - cross.X),
  872. point2.Y == cross.Y ? CorridorWidth : Mathf.Abs(point2.Y - cross.Y)
  873. );
  874.  
  875. Vector2 collPos1;
  876. Vector2 collSize1;
  877. if (point1.X == cross.X) //纵向加宽, 防止贴到其它墙
  878. {
  879. collPos1 = new Vector2(pos1.X - 3, pos1.Y);
  880. collSize1 = new Vector2(size1.X + 6, size1.Y);
  881. }
  882. else //横向加宽, 防止贴到其它墙
  883. {
  884. collPos1 = new Vector2(pos1.X, pos1.Y - 3);
  885. collSize1 = new Vector2(size1.X, size1.Y + 6);
  886. }
  887.  
  888. if (_roomGrid.RectCollision(collPos1, collSize1))
  889. {
  890. return false;
  891. }
  892.  
  893. Vector2 collPos2;
  894. Vector2 collSize2;
  895. if (point2.X == cross.X) //纵向加宽, 防止贴到其它墙
  896. {
  897. collPos2 = new Vector2(pos2.X - 3, pos2.Y);
  898. collSize2 = new Vector2(size2.X + 6, size2.Y);
  899. }
  900. else //横向加宽, 防止贴到其它墙
  901. {
  902. collPos2 = new Vector2(pos2.X, pos2.Y - 3);
  903. collSize2 = new Vector2(size2.X, size2.Y + 6);
  904. }
  905.  
  906. if (_roomGrid.RectCollision(collPos2, collSize2))
  907. {
  908. return false;
  909. }
  910.  
  911. _roomGrid.AddRect(pos1, size1, true);
  912. _roomGrid.AddRect(pos2, size2, true);
  913. return true;
  914. }
  915. }