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