Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / DungeonTileMap.cs
@小李xl 小李xl on 23 Aug 2023 59 KB 恢复加载地牢
  1.  
  2. using System.Collections.Generic;
  3. using Godot;
  4.  
  5. /// <summary>
  6. /// 地牢地砖管理类, 提供一些操作 TileMap 和计算导航的接口
  7. /// </summary>
  8. public class DungeonTileMap
  9. {
  10. //--------------------- 导航 -------------------------
  11. //已经标记过的点
  12. private readonly HashSet<Vector2I> _usePoints = new HashSet<Vector2I>();
  13.  
  14. //导航区域数据
  15. private readonly List<NavigationPolygonData> _polygonDataList = new List<NavigationPolygonData>();
  16.  
  17. //连接门的导航区域
  18. private readonly List<DoorNavigationInfo> _connectNavigationItemList = new List<DoorNavigationInfo>();
  19. //----------------------------------------------------
  20. private TileMap _tileRoot;
  21. //地面地砖在 Atlas 的位置
  22. private List<Vector2I> _floorAtlasCoords;
  23. //生成导航的结果
  24. private GenerateNavigationResult _generateNavigationResult;
  25.  
  26. public DungeonTileMap(TileMap tileRoot)
  27. {
  28. _tileRoot = tileRoot;
  29. }
  30.  
  31. /// <summary>
  32. /// 根据 startRoom 和 config 数据自动填充 tileMap 参数中的地图数据
  33. /// </summary>
  34. public void AutoFillRoomTile(AutoTileConfig config, RoomInfo startRoom, SeedRandom random)
  35. {
  36. _connectNavigationItemList.Clear();
  37. _AutoFillRoomTile(config, startRoom, random);
  38. }
  39. private void _AutoFillRoomTile(AutoTileConfig config, RoomInfo roomInfo, SeedRandom random)
  40. {
  41. foreach (var info in roomInfo.Next)
  42. {
  43. _AutoFillRoomTile(config, info, random);
  44. }
  45. //铺房间
  46. if (roomInfo.RoomSplit == null)
  47. {
  48. FillRect(GameConfig.FloorMapLayer, config.Floor, roomInfo.Position + Vector2.One,
  49. roomInfo.Size - new Vector2(2, 2));
  50.  
  51. FillRect(GameConfig.TopMapLayer, config.IN_LT, roomInfo.Position, Vector2.One);
  52. FillRect(GameConfig.TopMapLayer, config.L, roomInfo.Position + new Vector2(0, 1),
  53. new Vector2(1, roomInfo.Size.Y - 2));
  54. FillRect(GameConfig.TopMapLayer, config.IN_LB, roomInfo.Position + new Vector2(0, roomInfo.Size.Y - 1),
  55. new Vector2(1, 1));
  56. FillRect(GameConfig.TopMapLayer, config.B, roomInfo.Position + new Vector2(1, roomInfo.Size.Y - 1),
  57. new Vector2(roomInfo.Size.X - 2, 1));
  58. FillRect(GameConfig.TopMapLayer, config.IN_RB,
  59. roomInfo.Position + new Vector2(roomInfo.Size.X - 1, roomInfo.Size.Y - 1),
  60. Vector2.One);
  61. FillRect(GameConfig.TopMapLayer, config.R, roomInfo.Position + new Vector2(roomInfo.Size.X - 1, 1),
  62. new Vector2(1, roomInfo.Size.Y - 2));
  63. FillRect(GameConfig.TopMapLayer, config.IN_RT, roomInfo.Position + new Vector2(roomInfo.Size.X - 1, 0),
  64. Vector2.One);
  65. FillRect(GameConfig.MiddleMapLayer, config.T, roomInfo.Position + Vector2.Right,
  66. new Vector2(roomInfo.Size.X - 2, 1));
  67. }
  68. else
  69. {
  70. var rectSize = roomInfo.RoomSplit.RoomInfo.Size;
  71. var rectPos = roomInfo.RoomSplit.RoomInfo.Position;
  72. var offset = roomInfo.GetOffsetPosition() / GameConfig.TileCellSizeVector2I;
  73. //填充tile操作
  74. var tileInfo = roomInfo.RoomSplit.TileInfo;
  75. for (var i = 0; i < tileInfo.Floor.Count; i += 5)
  76. {
  77. var posX = tileInfo.Floor[i];
  78. var posY = tileInfo.Floor[i + 1];
  79. var sourceId = tileInfo.Floor[i + 2];
  80. var atlasCoordsX = tileInfo.Floor[i + 3];
  81. var atlasCoordsY = tileInfo.Floor[i + 4];
  82. var pos = new Vector2I(roomInfo.Position.X + posX - offset.X, roomInfo.Position.Y + posY - offset.Y);
  83. _tileRoot.SetCell(GameConfig.FloorMapLayer, pos, sourceId, new Vector2I(atlasCoordsX, atlasCoordsY));
  84. }
  85. for (var i = 0; i < tileInfo.Middle.Count; i += 5)
  86. {
  87. var posX = tileInfo.Middle[i];
  88. var posY = tileInfo.Middle[i + 1];
  89. var sourceId = tileInfo.Middle[i + 2];
  90. var atlasCoordsX = tileInfo.Middle[i + 3];
  91. var atlasCoordsY = tileInfo.Middle[i + 4];
  92. var pos = new Vector2I(roomInfo.Position.X + posX - offset.X, roomInfo.Position.Y + posY - offset.Y);
  93. _tileRoot.SetCell(GameConfig.MiddleMapLayer, pos, sourceId, new Vector2I(atlasCoordsX, atlasCoordsY));
  94. }
  95. for (var i = 0; i < tileInfo.Top.Count; i += 5)
  96. {
  97. var posX = tileInfo.Top[i];
  98. var posY = tileInfo.Top[i + 1];
  99. var sourceId = tileInfo.Top[i + 2];
  100. var atlasCoordsX = tileInfo.Top[i + 3];
  101. var atlasCoordsY = tileInfo.Top[i + 4];
  102. var pos = new Vector2I(roomInfo.Position.X + posX - offset.X, roomInfo.Position.Y + posY - offset.Y);
  103. _tileRoot.SetCell(GameConfig.TopMapLayer, pos, sourceId, new Vector2I(atlasCoordsX, atlasCoordsY));
  104. }
  105.  
  106. GD.PrintErr("初始化流程得改");
  107. //roomInfo.RoomSplit.TileInfo.
  108. // var template = ResourceManager.Load<PackedScene>(roomInfo.RoomSplit.ScenePath);
  109. // var tileInstance = template.Instantiate<DungeonRoomTemplate>();
  110. //
  111. // //其它物体
  112. // var childCount = tileInstance.GetChildCount();
  113. // for (var i = 0; i < childCount; i++)
  114. // {
  115. // var item = tileInstance.GetChild(i);
  116. // if (!(item is ActivityMark))
  117. // {
  118. // item.GetParent().RemoveChild(item);
  119. // item.Owner = null;
  120. // _tileRoot.AddChild(item);
  121. // if (item is Node2D node)
  122. // {
  123. // node.Position = roomInfo.GetWorldPosition() + (node.GlobalPosition - offset);
  124. // }
  125. //
  126. // i--;
  127. // childCount--;
  128. // }
  129. // }
  130. //
  131. // //物体标记
  132. // var activityMarks = tileInstance.GetMarks();
  133. // foreach (var activityMark in activityMarks)
  134. // {
  135. // var pos = activityMark.Position;
  136. // activityMark.GetParent().RemoveChild(activityMark);
  137. // activityMark.Owner = null;
  138. // //_tileRoot.AddChild(activityMark);
  139. // activityMark.Position = roomInfo.GetWorldPosition() + (pos - offset);
  140. // activityMark.TileRoot = _tileRoot;
  141. // //执行预处理操作
  142. // activityMark.Pretreatment(random);
  143. // }
  144. // roomInfo.ActivityMarks.AddRange(activityMarks);
  145. //
  146. // //填充tile操作
  147. // for (int i = 0; i < rectSize.X; i++)
  148. // {
  149. // for (int j = 0; j < rectSize.Y; j++)
  150. // {
  151. // var coords = new Vector2I((int)(rectPos.X + i), (int)(rectPos.Y + j));
  152. // var atlasCoords = tileInstance.GetCellAtlasCoords(0, coords);
  153. // if (atlasCoords.X != -1 && atlasCoords.Y != -1)
  154. // {
  155. // // 在 Godot 4.0 中使用以下这段代码区分层级, 会导致游戏关闭时有概率报错卡死, 目前尚不清楚原因
  156. // //获取自定义层级
  157. // // var customData = tileInstance.GetCellTileData(0, coords).GetCustomData(CustomTileLayerName);
  158. // // var layer = customData.AsInt32();
  159. // // layer = Mathf.Clamp(layer, GameConfig.FloorMapLayer, GameConfig.TopMapLayer);
  160. //
  161. // var layer = config.GetLayer(atlasCoords);
  162. // _tileRoot.SetCell(layer, new Vector2I(roomInfo.Position.X + i, roomInfo.Position.Y + j),
  163. // 0, atlasCoords);
  164. // }
  165. // }
  166. // }
  167. //
  168. // tileInstance.CallDeferred(Node.MethodName.QueueFree);
  169. }
  170.  
  171. //铺过道
  172. foreach (var doorInfo in roomInfo.Doors)
  173. {
  174. if (doorInfo.ConnectRoom.Id > roomInfo.Id)
  175. {
  176. //普通的直线连接
  177. var doorDir1 = doorInfo.Direction;
  178. var doorDir2 = doorInfo.ConnectDoor.Direction;
  179. if (!doorInfo.HasCross)
  180. {
  181. var rect = Utils.CalcRect(
  182. doorInfo.OriginPosition.X,
  183. doorInfo.OriginPosition.Y,
  184. doorInfo.ConnectDoor.OriginPosition.X,
  185. doorInfo.ConnectDoor.OriginPosition.Y
  186. );
  187. switch (doorDir1)
  188. {
  189. case DoorDirection.E:
  190. rect.Size = new Vector2(rect.Size.X, GameConfig.CorridorWidth);
  191. FullHorizontalAisle(config, rect);
  192. FullHorizontalAisleLeft(config, rect, doorInfo);
  193. FullHorizontalAisleRight(config, rect, doorInfo.ConnectDoor);
  194. break;
  195. case DoorDirection.W:
  196. rect.Size = new Vector2(rect.Size.X, GameConfig.CorridorWidth);
  197. FullHorizontalAisle(config, rect);
  198. FullHorizontalAisleLeft(config, rect, doorInfo.ConnectDoor);
  199. FullHorizontalAisleRight(config, rect, doorInfo);
  200. break;
  201. case DoorDirection.S:
  202. rect.Size = new Vector2(GameConfig.CorridorWidth, rect.Size.Y);
  203. FullVerticalAisle(config, rect);
  204. FullVerticalAisleUp(config, rect, doorInfo);
  205. FullVerticalAisleDown(config, rect, doorInfo.ConnectDoor);
  206. break;
  207. case DoorDirection.N:
  208. rect.Size = new Vector2(GameConfig.CorridorWidth, rect.Size.Y);
  209. FullVerticalAisle(config, rect);
  210. FullVerticalAisleUp(config, rect, doorInfo.ConnectDoor);
  211. FullVerticalAisleDown(config, rect, doorInfo);
  212. break;
  213. }
  214. }
  215. else //带交叉点
  216. {
  217. //方向, 0横向, 1纵向
  218. var dir1 = 0;
  219. var dir2 = 0;
  220. Rect2 rect;
  221. Rect2 rect2;
  222. //计算范围
  223. switch (doorDir1)
  224. {
  225. case DoorDirection.E: //→
  226. rect = new Rect2(
  227. doorInfo.OriginPosition.X,
  228. doorInfo.OriginPosition.Y,
  229. doorInfo.Cross.X - doorInfo.OriginPosition.X,
  230. GameConfig.CorridorWidth
  231. );
  232. break;
  233. case DoorDirection.W: //←
  234. rect = new Rect2(
  235. doorInfo.Cross.X + GameConfig.CorridorWidth,
  236. doorInfo.Cross.Y,
  237. doorInfo.OriginPosition.X - (doorInfo.Cross.X + GameConfig.CorridorWidth),
  238. GameConfig.CorridorWidth
  239. );
  240. break;
  241. case DoorDirection.S: //↓
  242. dir1 = 1;
  243. rect = new Rect2(
  244. doorInfo.OriginPosition.X,
  245. doorInfo.OriginPosition.Y,
  246. GameConfig.CorridorWidth,
  247. doorInfo.Cross.Y - doorInfo.OriginPosition.Y
  248. );
  249. break;
  250. case DoorDirection.N: //↑
  251. dir1 = 1;
  252. rect = new Rect2(
  253. doorInfo.Cross.X,
  254. doorInfo.Cross.Y + GameConfig.CorridorWidth,
  255. GameConfig.CorridorWidth,
  256. doorInfo.OriginPosition.Y - (doorInfo.Cross.Y + GameConfig.CorridorWidth)
  257. );
  258. break;
  259. default:
  260. rect = new Rect2();
  261. break;
  262. }
  263. switch (doorDir2)
  264. {
  265. case DoorDirection.E: //→
  266. rect2 = new Rect2(
  267. doorInfo.ConnectDoor.OriginPosition.X,
  268. doorInfo.ConnectDoor.OriginPosition.Y,
  269. doorInfo.Cross.X - doorInfo.ConnectDoor.OriginPosition.X,
  270. GameConfig.CorridorWidth
  271. );
  272. break;
  273. case DoorDirection.W: //←
  274. rect2 = new Rect2(
  275. doorInfo.Cross.X + GameConfig.CorridorWidth,
  276. doorInfo.Cross.Y,
  277. doorInfo.ConnectDoor.OriginPosition.X -
  278. (doorInfo.Cross.X + GameConfig.CorridorWidth),
  279. GameConfig.CorridorWidth
  280. );
  281. break;
  282. case DoorDirection.S: //↓
  283. dir2 = 1;
  284. rect2 = new Rect2(
  285. doorInfo.ConnectDoor.OriginPosition.X,
  286. doorInfo.ConnectDoor.OriginPosition.Y,
  287. GameConfig.CorridorWidth,
  288. doorInfo.Cross.Y - doorInfo.ConnectDoor.OriginPosition.Y
  289. );
  290. break;
  291. case DoorDirection.N: //↑
  292. dir2 = 1;
  293. rect2 = new Rect2(
  294. doorInfo.Cross.X,
  295. doorInfo.Cross.Y + GameConfig.CorridorWidth,
  296. GameConfig.CorridorWidth,
  297. doorInfo.ConnectDoor.OriginPosition.Y -
  298. (doorInfo.Cross.Y + GameConfig.CorridorWidth)
  299. );
  300. break;
  301. default:
  302. rect2 = new Rect2();
  303. break;
  304. }
  305. FillRect(GameConfig.AisleFloorMapLayer, config.Floor, doorInfo.Cross + Vector2.One,
  306. new Vector2(GameConfig.CorridorWidth - 2, GameConfig.CorridorWidth - 2));
  307. //墙壁, 0横向, 1纵向
  308. if (dir1 == 0)
  309. {
  310. FullHorizontalAisle(config, rect);
  311. FullHorizontalAisleLeft(config, rect, doorDir1 == DoorDirection.E ? doorInfo : null);
  312. FullHorizontalAisleRight(config, rect, doorDir1 == DoorDirection.W ? doorInfo : null);
  313. }
  314. else
  315. {
  316. FullVerticalAisle(config, rect);
  317. FullVerticalAisleUp(config, rect, doorDir1 == DoorDirection.S ? doorInfo : null);
  318. FullVerticalAisleDown(config, rect, doorDir1 == DoorDirection.N ? doorInfo : null);
  319. }
  320. if (dir2 == 0)
  321. {
  322. FullHorizontalAisle(config, rect2);
  323. FullHorizontalAisleLeft(config, rect2, doorDir2 == DoorDirection.E ? doorInfo.ConnectDoor : null);
  324. FullHorizontalAisleRight(config, rect2, doorDir2 == DoorDirection.W ? doorInfo.ConnectDoor : null);
  325. }
  326. else
  327. {
  328. FullVerticalAisle(config, rect2);
  329. FullVerticalAisleUp(config, rect2, doorDir2 == DoorDirection.S ? doorInfo.ConnectDoor : null);
  330. FullVerticalAisleDown(config, rect2, doorDir2 == DoorDirection.N ? doorInfo.ConnectDoor : null);
  331. }
  332. if ((doorDir1 == DoorDirection.N && doorDir2 == DoorDirection.E) || //↑→
  333. (doorDir2 == DoorDirection.N && doorDir1 == DoorDirection.E))
  334. {
  335. FillRect(GameConfig.TopMapLayer, config.OUT_RT,
  336. doorInfo.Cross + new Vector2(0, GameConfig.CorridorWidth - 1),
  337. Vector2.One);
  338. FillRect(GameConfig.TopMapLayer, config.IN_RT, doorInfo.Cross + new Vector2(GameConfig.CorridorWidth - 1, 0),
  339. Vector2.One);
  340. FillRect(GameConfig.MiddleMapLayer, config.T, doorInfo.Cross, new Vector2(GameConfig.CorridorWidth - 1, 1));
  341. FillRect(GameConfig.TopMapLayer, config.R, doorInfo.Cross + new Vector2(GameConfig.CorridorWidth - 1, 1),
  342. new Vector2(1, GameConfig.CorridorWidth - 1));
  343. }
  344. else if ((doorDir1 == DoorDirection.E && doorDir2 == DoorDirection.S) || //→↓
  345. (doorDir2 == DoorDirection.E && doorDir1 == DoorDirection.S))
  346. {
  347. FillRect(GameConfig.MiddleMapLayer, config.OUT_RB, doorInfo.Cross, Vector2.One);
  348. FillRect(GameConfig.TopMapLayer, config.IN_RB,
  349. doorInfo.Cross + new Vector2(GameConfig.CorridorWidth - 1,
  350. GameConfig.CorridorWidth - 1),
  351. Vector2.One);
  352. FillRect(GameConfig.TopMapLayer, config.R, doorInfo.Cross + new Vector2(GameConfig.CorridorWidth - 1, 0),
  353. new Vector2(1, GameConfig.CorridorWidth - 1));
  354. FillRect(GameConfig.TopMapLayer, config.B, doorInfo.Cross + new Vector2(0, GameConfig.CorridorWidth - 1),
  355. new Vector2(GameConfig.CorridorWidth - 1, 1));
  356. }
  357. else if ((doorDir1 == DoorDirection.S && doorDir2 == DoorDirection.W) || //↓←
  358. (doorDir2 == DoorDirection.S && doorDir1 == DoorDirection.W))
  359. {
  360. FillRect(GameConfig.MiddleMapLayer, config.OUT_LB,
  361. doorInfo.Cross + new Vector2(GameConfig.CorridorWidth - 1, 0), Vector2.One);
  362. FillRect(GameConfig.TopMapLayer, config.IN_LB, doorInfo.Cross + new Vector2(0, GameConfig.CorridorWidth - 1),
  363. Vector2.One);
  364. FillRect(GameConfig.TopMapLayer, config.L, doorInfo.Cross, new Vector2(1, GameConfig.CorridorWidth - 1));
  365. FillRect(GameConfig.TopMapLayer, config.B, doorInfo.Cross + new Vector2(1, GameConfig.CorridorWidth - 1),
  366. new Vector2(GameConfig.CorridorWidth - 1, 1));
  367. }
  368. else if ((doorDir1 == DoorDirection.W && doorDir2 == DoorDirection.N) || //←↑
  369. (doorDir2 == DoorDirection.W && doorDir1 == DoorDirection.N))
  370. {
  371. FillRect(GameConfig.TopMapLayer, config.OUT_LT,
  372. doorInfo.Cross + new Vector2(GameConfig.CorridorWidth - 1,
  373. GameConfig.CorridorWidth - 1),
  374. Vector2.One);
  375. FillRect(GameConfig.TopMapLayer, config.IN_LT, doorInfo.Cross, Vector2.One);
  376. FillRect(GameConfig.MiddleMapLayer, config.T, doorInfo.Cross + new Vector2(1, 0),
  377. new Vector2(GameConfig.CorridorWidth - 1, 1));
  378. FillRect(GameConfig.TopMapLayer, config.L, doorInfo.Cross + new Vector2(0, 1),
  379. new Vector2(1, GameConfig.CorridorWidth - 1));
  380. }
  381. //在房间墙上开洞
  382. switch (doorDir1)
  383. {
  384. case DoorDirection.E: //→
  385. ClearRect(GameConfig.TopMapLayer, doorInfo.OriginPosition + new Vector2(-1, 1),
  386. new Vector2(1, rect.Size.Y - 2));
  387. break;
  388. case DoorDirection.W: //←
  389. ClearRect(GameConfig.TopMapLayer, doorInfo.OriginPosition + new Vector2(0, 1),
  390. new Vector2(1, rect.Size.Y - 2));
  391. break;
  392. case DoorDirection.S: //↓
  393. ClearRect(GameConfig.TopMapLayer, doorInfo.OriginPosition + new Vector2(1, -1),
  394. new Vector2(rect.Size.X - 2, 1));
  395. break;
  396. case DoorDirection.N: //↑
  397. ClearRect(GameConfig.MiddleMapLayer, doorInfo.OriginPosition + new Vector2(1, 2),
  398. new Vector2(rect.Size.X - 2, 1));
  399. break;
  400. }
  401. switch (doorDir2)
  402. {
  403. case DoorDirection.E: //→
  404. ClearRect(GameConfig.TopMapLayer, doorInfo.ConnectDoor.OriginPosition + new Vector2(-1, 1),
  405. new Vector2(1, rect2.Size.Y - 2));
  406. break;
  407. case DoorDirection.W: //←
  408. ClearRect(GameConfig.TopMapLayer, doorInfo.ConnectDoor.OriginPosition + new Vector2(0, 1),
  409. new Vector2(1, rect2.Size.Y - 2));
  410. break;
  411. case DoorDirection.S: //↓
  412. ClearRect(GameConfig.TopMapLayer, doorInfo.ConnectDoor.OriginPosition + new Vector2(1, -1),
  413. new Vector2(rect2.Size.X - 2, 1));
  414. break;
  415. case DoorDirection.N: //↑
  416. ClearRect(GameConfig.MiddleMapLayer, doorInfo.ConnectDoor.OriginPosition + new Vector2(1, 0),
  417. new Vector2(rect2.Size.X - 2, 1));
  418. break;
  419. }
  420. }
  421. }
  422. }
  423. }
  424.  
  425. //填充tile区域
  426. private void FillRect(int layer, TileCellInfo info, Vector2 pos, Vector2 size)
  427. {
  428. for (int i = 0; i < size.X; i++)
  429. {
  430. for (int j = 0; j < size.Y; j++)
  431. {
  432. _tileRoot.SetCell(layer, new Vector2I((int)pos.X + i, (int)pos.Y + j), 0, info.AutoTileCoord);
  433. }
  434. }
  435. }
  436.  
  437. //清除tile区域
  438. private void ClearRect(int layer, Vector2 pos, Vector2 size)
  439. {
  440. for (int i = 0; i < size.X; i++)
  441. {
  442. for (int j = 0; j < size.Y; j++)
  443. {
  444. _tileRoot.SetCell(layer, new Vector2I((int)pos.X + i, (int)pos.Y + j), 0);
  445. }
  446. }
  447. }
  448.  
  449. //横向过道
  450. private void FullHorizontalAisle(AutoTileConfig config, Rect2 rect)
  451. {
  452. FillRect(GameConfig.AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(0, 1), rect.Size - new Vector2(0, 2));
  453. FillRect(GameConfig.MiddleMapLayer, config.T, rect.Position, new Vector2(rect.Size.X, 1));
  454. FillRect(GameConfig.TopMapLayer, config.B, rect.Position + new Vector2(0, rect.Size.Y - 1), new Vector2(rect.Size.X, 1));
  455. }
  456.  
  457. //纵向过道
  458. private void FullVerticalAisle(AutoTileConfig config, Rect2 rect)
  459. {
  460. FillRect(GameConfig.AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(1, 0), rect.Size - new Vector2(2, 0));
  461. FillRect(GameConfig.TopMapLayer, config.L, rect.Position, new Vector2(1, rect.Size.Y));
  462. FillRect(GameConfig.TopMapLayer, config.R, rect.Position + new Vector2(rect.Size.X - 1, 0), new Vector2(1, rect.Size.Y));
  463. }
  464.  
  465. //横向过道, 门朝右, 连接方向向左
  466. private void FullHorizontalAisleLeft(AutoTileConfig config, Rect2 rect, RoomDoorInfo doorInfo = null)
  467. {
  468. //左
  469. ClearRect(GameConfig.TopMapLayer, rect.Position + new Vector2(-1, 1), new Vector2(1, rect.Size.Y - 2));
  470. if (doorInfo == null)
  471. {
  472. FillRect(GameConfig.AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(-1, 1),
  473. new Vector2(1, rect.Size.Y - 2));
  474. }
  475. else
  476. {
  477. ClearRect(GameConfig.TopMapLayer, rect.Position + new Vector2(-1, 0), Vector2.One);
  478. FillRect(GameConfig.MiddleMapLayer, config.OUT_LB, rect.Position + new Vector2(-1, 0), Vector2.One);
  479. FillRect(GameConfig.TopMapLayer, config.OUT_LT, rect.Position + new Vector2(-1, 3), Vector2.One);
  480. FillRect(GameConfig.FloorMapLayer, config.Floor, rect.Position + new Vector2(-1, 1), new Vector2(1, rect.Size.Y - 2));
  481. //生成门的导航区域
  482. var x = rect.Position.X * GameConfig.TileCellSize;
  483. var y = rect.Position.Y * GameConfig.TileCellSize;
  484. var op1 = new Vector2(x - GameConfig.TileCellSize * 1.5f, y + GameConfig.TileCellSize * 1.5f);
  485. var op2 = new Vector2(x + GameConfig.TileCellSize * 0.5f, y + GameConfig.TileCellSize * 1.5f);
  486. var op3 = new Vector2(x + GameConfig.TileCellSize * 0.5f, y + GameConfig.TileCellSize * 3f);
  487. var op4 = new Vector2(x - GameConfig.TileCellSize * 1.5f, y + GameConfig.TileCellSize * 3f);
  488. AddDoorNavigation(
  489. doorInfo, op1, op2, op3, op4,
  490. op1,
  491. new Vector2(op1.X + GameConfig.TileCellSize, op2.Y),
  492. new Vector2(op1.X + GameConfig.TileCellSize, op3.Y),
  493. op4
  494. );
  495. }
  496. }
  497. //横向过道, 门朝左, 连接方向向右
  498. private void FullHorizontalAisleRight(AutoTileConfig config, Rect2 rect, RoomDoorInfo doorInfo = null)
  499. {
  500. //右
  501. ClearRect(GameConfig.TopMapLayer, rect.Position + new Vector2(rect.Size.X, 1), new Vector2(1, rect.Size.Y - 2));
  502. if (doorInfo == null)
  503. {
  504. FillRect(GameConfig.AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(rect.Size.X, 1), new Vector2(1, rect.Size.Y - 2));
  505. }
  506. else
  507. {
  508. ClearRect(GameConfig.TopMapLayer, rect.Position + new Vector2(rect.Size.X, 0), Vector2.One);
  509. FillRect(GameConfig.MiddleMapLayer, config.OUT_RB, rect.Position + new Vector2(rect.Size.X, 0), Vector2.One);
  510. FillRect(GameConfig.TopMapLayer, config.OUT_RT, rect.Position + new Vector2(rect.Size.X, 3), Vector2.One);
  511. FillRect(GameConfig.FloorMapLayer, config.Floor, rect.Position + new Vector2(rect.Size.X, 1), new Vector2(1, rect.Size.Y - 2));
  512. //生成门的导航区域
  513. var x = rect.Position.X * GameConfig.TileCellSize;
  514. var y = rect.Position.Y * GameConfig.TileCellSize;
  515. var op1 = new Vector2(x - GameConfig.TileCellSize * 1.5f + (rect.Size.X + 1) * GameConfig.TileCellSize, y + GameConfig.TileCellSize * 1.5f);
  516. var op2 = new Vector2(x + GameConfig.TileCellSize * 0.5f + (rect.Size.X + 1) * GameConfig.TileCellSize, y + GameConfig.TileCellSize * 1.5f);
  517. var op3 = new Vector2(x + GameConfig.TileCellSize * 0.5f + (rect.Size.X + 1) * GameConfig.TileCellSize, y + GameConfig.TileCellSize * 3f);
  518. var op4 = new Vector2(x - GameConfig.TileCellSize * 1.5f + (rect.Size.X + 1) * GameConfig.TileCellSize, y + GameConfig.TileCellSize * 3f);
  519. AddDoorNavigation(
  520. doorInfo, op1, op2, op3, op4,
  521. new Vector2(op2.X - GameConfig.TileCellSize, op1.Y),
  522. op2,
  523. op3,
  524. new Vector2(op2.X - GameConfig.TileCellSize, op4.Y)
  525. );
  526. }
  527. }
  528.  
  529. //纵向过道, 门朝下, 连接方向向上
  530. private void FullVerticalAisleUp(AutoTileConfig config, Rect2 rect, RoomDoorInfo doorInfo = null)
  531. {
  532. //上
  533. ClearRect(GameConfig.TopMapLayer, rect.Position + new Vector2(1, -1), new Vector2(rect.Size.X - 2, 1));
  534. if (doorInfo == null)
  535. {
  536. FillRect(GameConfig.AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(1, -1),
  537. new Vector2(rect.Size.X - 2, 1));
  538. }
  539. else
  540. {
  541. FillRect(GameConfig.TopMapLayer, config.OUT_RT, rect.Position + new Vector2(0, -1), Vector2.One);
  542. FillRect(GameConfig.TopMapLayer, config.OUT_LT, rect.Position + new Vector2(3, -1), Vector2.One);
  543. FillRect(GameConfig.FloorMapLayer, config.Floor, rect.Position + new Vector2(1, -1), new Vector2(rect.Size.X - 2, 1));
  544. //生成门的导航区域
  545. var x = rect.Position.X * GameConfig.TileCellSize;
  546. var y = rect.Position.Y * GameConfig.TileCellSize;
  547. var op1 = new Vector2(x + GameConfig.TileCellSize * 1.5f, y - GameConfig.TileCellSize * 1f);
  548. var op2 = new Vector2(x + GameConfig.TileCellSize * 2.5f, y - GameConfig.TileCellSize * 1f);
  549. var op3 = new Vector2(x + GameConfig.TileCellSize * 2.5f, y + GameConfig.TileCellSize * 0.5f);
  550. var op4 = new Vector2(x + GameConfig.TileCellSize * 1.5f, y + GameConfig.TileCellSize * 0.5f);
  551. AddDoorNavigation(
  552. doorInfo, op1, op2, op3, op4,
  553. op1,
  554. op2,
  555. new Vector2(op3.X, op1.Y + GameConfig.TileCellSize),
  556. new Vector2(op4.X, op1.Y + GameConfig.TileCellSize)
  557. );
  558. }
  559. }
  560. //纵向过道, 门朝上, 连接方向向下
  561. private void FullVerticalAisleDown(AutoTileConfig config, Rect2 rect, RoomDoorInfo doorInfo = null)
  562. {
  563. //下
  564. ClearRect(GameConfig.MiddleMapLayer, rect.Position + new Vector2(1, rect.Size.Y), new Vector2(rect.Size.X - 2, 1));
  565. if (doorInfo == null)
  566. {
  567. FillRect(GameConfig.AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(1, rect.Size.Y), new Vector2(rect.Size.X - 2, 1));
  568. }
  569. else
  570. {
  571. FillRect(GameConfig.MiddleMapLayer, config.OUT_RB, rect.Position + new Vector2(0, rect.Size.Y), Vector2.One);
  572. FillRect(GameConfig.MiddleMapLayer, config.OUT_LB, rect.Position + new Vector2(3, rect.Size.Y), Vector2.One);
  573. FillRect(GameConfig.FloorMapLayer, config.Floor, rect.Position + new Vector2(1, rect.Size.Y), new Vector2(rect.Size.X - 2, 1));
  574. //生成门的导航区域
  575. var x = rect.Position.X * GameConfig.TileCellSize;
  576. var y = rect.Position.Y * GameConfig.TileCellSize;
  577. var op1 = new Vector2(x + GameConfig.TileCellSize * 1.5f, y - GameConfig.TileCellSize * 1f + (rect.Size.Y + 1) * GameConfig.TileCellSize);
  578. var op2 = new Vector2(x + GameConfig.TileCellSize * 2.5f, y - GameConfig.TileCellSize * 1f + (rect.Size.Y + 1) * GameConfig.TileCellSize);
  579. var op3 = new Vector2(x + GameConfig.TileCellSize * 2.5f, y + GameConfig.TileCellSize * 0.5f + (rect.Size.Y + 1) * GameConfig.TileCellSize);
  580. var op4 = new Vector2(x + GameConfig.TileCellSize * 1.5f, y + GameConfig.TileCellSize * 0.5f + (rect.Size.Y + 1) * GameConfig.TileCellSize);
  581. AddDoorNavigation(
  582. doorInfo, op1, op2, op3, op4,
  583. new Vector2(op1.X, op3.Y - GameConfig.TileCellSize),
  584. new Vector2(op2.X, op3.Y - GameConfig.TileCellSize),
  585. op3,
  586. op4
  587. );
  588. }
  589. }
  590.  
  591. /// <summary>
  592. /// 添加房间
  593. /// </summary>
  594. private void AddDoorNavigation(RoomDoorInfo doorInfo,
  595. Vector2 op1, Vector2 op2, Vector2 op3, Vector2 op4,
  596. Vector2 cp1, Vector2 cp2, Vector2 cp3, Vector2 cp4)
  597. {
  598. var openPolygonData = new NavigationPolygonData();
  599. openPolygonData.Type = NavigationPolygonType.Out;
  600. openPolygonData.SetPoints(new []{ op1, op2, op3, op4 });
  601.  
  602. var closePolygonData = new NavigationPolygonData();
  603. closePolygonData.Type = NavigationPolygonType.Out;
  604. closePolygonData.SetPoints(new []{ cp1, cp2, cp3, cp4 });
  605.  
  606. _connectNavigationItemList.Add(new DoorNavigationInfo(doorInfo, openPolygonData, closePolygonData));
  607. }
  608.  
  609. /// <summary>
  610. /// 计算并动生成导航区域, layer 为需要计算的层级,如果没有设置 floorAtlasCoords,则该 layer 下不为空的地砖都将视为可行走区域
  611. /// </summary>
  612. public void GenerateNavigationPolygon(int layer)
  613. {
  614. _usePoints.Clear();
  615. _polygonDataList.Clear();
  616.  
  617. try
  618. {
  619. var size = new Vector2(_tileRoot.CellQuadrantSize, _tileRoot.CellQuadrantSize);
  620.  
  621. var rect = _tileRoot.GetUsedRect();
  622.  
  623. var x = rect.Position.X;
  624. var y = rect.Position.Y;
  625. var w = rect.Size.X;
  626. var h = rect.Size.Y;
  627.  
  628. for (int j = y; j < h; j++)
  629. {
  630. for (int i = x; i < w; i++)
  631. {
  632. if (IsWayTile(layer, i, j))
  633. {
  634. if (!_usePoints.Contains(new Vector2I(i, j)))
  635. {
  636. NavigationPolygonData polygonData = null;
  637.  
  638. if (!IsWayTile(layer, i, j - 1))
  639. {
  640. polygonData = CalcOutline(layer, i, j, size);
  641. }
  642. else if (!IsWayTile(layer, i, j + 1))
  643. {
  644. polygonData = CalcInline(layer, i, j, size);
  645. }
  646.  
  647. if (polygonData != null)
  648. {
  649. _polygonDataList.Add(polygonData);
  650. }
  651. }
  652. }
  653. }
  654. }
  655.  
  656. _generateNavigationResult = new GenerateNavigationResult(true);
  657. }
  658. catch (NavigationPointInterleavingException e)
  659. {
  660. _usePoints.Clear();
  661. _polygonDataList.Clear();
  662. GD.Print(e.Message);
  663. _generateNavigationResult = new GenerateNavigationResult(false, e);
  664. }
  665. }
  666.  
  667. /// <summary>
  668. /// 获取生成导航区域操作的结果, 如果没有调用过 GenerateNavigationPolygon() 函数, 则返回 null
  669. /// </summary>
  670. /// <returns></returns>
  671. public GenerateNavigationResult GetGenerateNavigationResult()
  672. {
  673. return _generateNavigationResult;
  674. }
  675. /// <summary>
  676. /// 将导航区域挂载到 navigationRoot 上
  677. /// </summary>
  678. public void MountNavigationPolygon(Node2D navigationRoot)
  679. {
  680. //TestData();
  681. // 在 Godot4.0_rc6 中 如果将所有点都放在 NavigationPolygon 里面, 即使点是对的, 但调用 MakePolygonsFromOutlines 还是可能会报错, 这应该是个bug
  682. //通过 GenerateNavigationPolygon() 计算出来的导航区域
  683. for (var i = 0; i < _polygonDataList.Count; i++)
  684. {
  685. var polygonData = _polygonDataList[i];
  686. CreateNavigationRegion(navigationRoot, polygonData);
  687. }
  688.  
  689. //门占用区域的导航区域
  690. for (var i = 0; i < _connectNavigationItemList.Count; i++)
  691. {
  692. var item = _connectNavigationItemList[i];
  693. item.CloseNavigationNode = CreateNavigationRegion(navigationRoot, item.CloseNavigationData);
  694. item.OpenNavigationNode = CreateNavigationRegion(navigationRoot, item.OpenNavigationData);
  695. item.CloseNavigationNode.Enabled = false;
  696. item.OpenNavigationNode.Enabled = false;
  697. item.DoorInfo.Navigation = item;
  698. }
  699. }
  700.  
  701. //创建导航区域
  702. private NavigationRegion2D CreateNavigationRegion(Node2D navigationRoot, NavigationPolygonData polygonData)
  703. {
  704. var polygon = new NavigationPolygon();
  705. polygon.AddOutline(polygonData.GetPoints());
  706. polygon.MakePolygonsFromOutlines();
  707. var navigationPolygon = new NavigationRegion2D();
  708. navigationPolygon.Name = "NavigationRegion" + (navigationRoot.GetChildCount() + 1);
  709. navigationPolygon.NavigationPolygon = polygon;
  710. navigationRoot.AddChild(navigationPolygon);
  711. return navigationPolygon;
  712. }
  713.  
  714. /// <summary>
  715. /// 获取房间内的导航点数据
  716. /// </summary>
  717. public NavigationPolygonData[] GetPolygonData()
  718. {
  719. return _polygonDataList.ToArray();
  720. }
  721.  
  722. /// <summary>
  723. /// 设置导航网格数据
  724. /// </summary>
  725. /// <param name="list"></param>
  726. public void SetPolygonData(List<NavigationPolygonData> list)
  727. {
  728. _polygonDataList.Clear();
  729. _polygonDataList.AddRange(list);
  730. _generateNavigationResult = new GenerateNavigationResult(true);
  731. }
  732.  
  733. /// <summary>
  734. /// 清除生成的导航数据
  735. /// </summary>
  736. public void ClearPolygonData()
  737. {
  738. _polygonDataList.Clear();
  739. _generateNavigationResult = null;
  740. }
  741. /// <summary>
  742. /// 获取连接门导航数据, 必须要调用 AutoFillRoomTile() 函数才有数据
  743. /// </summary>
  744. public NavigationPolygonData[] GetConnectDoorPolygonData()
  745. {
  746. var array = new NavigationPolygonData[_connectNavigationItemList.Count];
  747. for (var i = 0; i < _connectNavigationItemList.Count; i++)
  748. {
  749. array[i] = _connectNavigationItemList[i].OpenNavigationData;
  750. }
  751. return array;
  752. }
  753.  
  754. /// <summary>
  755. /// 设置地面的地砖,将影响导航网格计算
  756. /// </summary>
  757. public void SetFloorAtlasCoords(List<Vector2I> floorAtlasCoords)
  758. {
  759. _floorAtlasCoords = floorAtlasCoords;
  760. }
  761. /// <summary>
  762. /// 返回指定位置的Tile是否为可以行走
  763. /// </summary>
  764. private bool IsWayTile(int layer, int x, int y)
  765. {
  766. if (_floorAtlasCoords == null || _floorAtlasCoords.Count == 0)
  767. {
  768. return _tileRoot.GetCellTileData(layer, new Vector2I(x, y)) != null;
  769. }
  770.  
  771. var result = _tileRoot.GetCellAtlasCoords(layer, new Vector2I(x, y));
  772. return _floorAtlasCoords.Contains(result);
  773. }
  774.  
  775. //计算导航网格外轮廓
  776. private NavigationPolygonData CalcOutline(int layer, int i, int j, Vector2 size)
  777. {
  778. var polygonData = new NavigationPolygonData();
  779. polygonData.Type = NavigationPolygonType.Out;
  780. var points = new List<Vector2>();
  781. // 0:右, 1:下, 2:左, 3:上
  782. var dir = 0;
  783. var offset = new Vector2(size.X * 0.5f, size.Y * 0.5f);
  784. //找到路, 向右开始找边界
  785. var startPos = new Vector2I(i, j);
  786.  
  787. var tempI = i;
  788. var tempJ = j;
  789.  
  790. while (true)
  791. {
  792. switch (dir)
  793. {
  794. case 0: //右
  795. {
  796. if (IsWayTile(layer, tempI, tempJ - 1)) //先向上找
  797. {
  798. dir = 3;
  799.  
  800. var pos = new Vector2I(tempI, tempJ);
  801. if (points.Count > 1 && pos == startPos)
  802. {
  803. polygonData.SetPoints(points.ToArray());
  804. return polygonData;
  805. }
  806.  
  807. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  808. PutUsePoint(pos);
  809.  
  810. tempJ--;
  811. break;
  812. }
  813. else if (IsWayTile(layer, tempI + 1, tempJ)) //再向右找
  814. {
  815. if (points.Count == 0)
  816. {
  817. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  818. }
  819.  
  820. var pos = new Vector2I(tempI, tempJ);
  821. if (points.Count > 1 && pos == startPos)
  822. {
  823. polygonData.SetPoints(points.ToArray());
  824. return polygonData;
  825. }
  826.  
  827. PutUsePoint(new Vector2I(tempI, tempJ));
  828. tempI++;
  829. break;
  830. }
  831. else if (IsWayTile(layer, tempI, tempJ + 1)) //向下找
  832. {
  833. dir = 1;
  834.  
  835. var pos = new Vector2I(tempI, tempJ);
  836. if (points.Count > 1 && pos == startPos)
  837. {
  838. polygonData.SetPoints(points.ToArray());
  839. return polygonData;
  840. }
  841.  
  842. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  843. PutUsePoint(pos);
  844.  
  845. tempJ++;
  846. break;
  847. }
  848.  
  849. throw new NavigationPointInterleavingException(new Vector2I(tempI, tempJ), "生成导航多边形发生错误! 点: " + new Vector2I(tempI, tempJ) + "发生交错!");
  850. }
  851. case 1: //下
  852. {
  853. if (IsWayTile(layer, tempI + 1, tempJ)) //先向右找
  854. {
  855. dir = 0;
  856.  
  857. var pos = new Vector2I(tempI, tempJ);
  858. if (points.Count > 1 && pos == startPos)
  859. {
  860. polygonData.SetPoints(points.ToArray());
  861. return polygonData;
  862. }
  863.  
  864. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  865. PutUsePoint(pos);
  866.  
  867. tempI++;
  868. break;
  869. }
  870. else if (IsWayTile(layer, tempI, tempJ + 1)) //再向下找
  871. {
  872. if (points.Count == 0)
  873. {
  874. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  875. }
  876.  
  877. var pos = new Vector2I(tempI, tempJ);
  878. if (points.Count > 1 && pos == startPos)
  879. {
  880. polygonData.SetPoints(points.ToArray());
  881. return polygonData;
  882. }
  883.  
  884. PutUsePoint(new Vector2I(tempI, tempJ));
  885. tempJ++;
  886. break;
  887. }
  888. else if (IsWayTile(layer, tempI - 1, tempJ)) //向左找
  889. {
  890. dir = 2;
  891.  
  892. var pos = new Vector2I(tempI, tempJ);
  893. if (points.Count > 1 && pos == startPos)
  894. {
  895. polygonData.SetPoints(points.ToArray());
  896. return polygonData;
  897. }
  898.  
  899. //points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  900. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y * 2));
  901. PutUsePoint(pos);
  902.  
  903. tempI--;
  904. break;
  905. }
  906.  
  907. throw new NavigationPointInterleavingException(new Vector2I(tempI, tempJ), "生成导航多边形发生错误! 点: " + new Vector2I(tempI, tempJ) + "发生交错!");
  908. }
  909. case 2: //左
  910. {
  911. if (IsWayTile(layer, tempI, tempJ + 1)) //先向下找
  912. {
  913. dir = 1;
  914.  
  915. var pos = new Vector2I(tempI, tempJ);
  916. if (points.Count > 1 && pos == startPos)
  917. {
  918. polygonData.SetPoints(points.ToArray());
  919. return polygonData;
  920. }
  921.  
  922. //points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  923. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y * 2));
  924. PutUsePoint(pos);
  925.  
  926. tempJ++;
  927. break;
  928. }
  929. else if (IsWayTile(layer, tempI - 1, tempJ)) //再向左找
  930. {
  931. if (points.Count == 0)
  932. {
  933. //points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  934. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y * 2));
  935. }
  936.  
  937. var pos = new Vector2I(tempI, tempJ);
  938. if (points.Count > 1 && pos == startPos)
  939. {
  940. polygonData.SetPoints(points.ToArray());
  941. return polygonData;
  942. }
  943.  
  944. PutUsePoint(new Vector2I(tempI, tempJ));
  945. tempI--;
  946. break;
  947. }
  948. else if (IsWayTile(layer, tempI, tempJ - 1)) //向上找
  949. {
  950. dir = 3;
  951.  
  952. var pos = new Vector2I(tempI, tempJ);
  953. if (points.Count > 1 && pos == startPos)
  954. {
  955. polygonData.SetPoints(points.ToArray());
  956. return polygonData;
  957. }
  958.  
  959. //points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  960. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y * 2));
  961. PutUsePoint(pos);
  962.  
  963. tempJ--;
  964. break;
  965. }
  966.  
  967. throw new NavigationPointInterleavingException(new Vector2I(tempI, tempJ), "生成导航多边形发生错误! 点: " + new Vector2I(tempI, tempJ) + "发生交错!");
  968. }
  969. case 3: //上
  970. {
  971. if (IsWayTile(layer, tempI - 1, tempJ)) //先向左找
  972. {
  973. dir = 2;
  974.  
  975. var pos = new Vector2I(tempI, tempJ);
  976. if (points.Count > 1 && pos == startPos)
  977. {
  978. polygonData.SetPoints(points.ToArray());
  979. return polygonData;
  980. }
  981.  
  982. //points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  983. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y * 2));
  984. PutUsePoint(pos);
  985.  
  986. tempI--;
  987. break;
  988. }
  989. else if (IsWayTile(layer, tempI, tempJ - 1)) //再向上找
  990. {
  991. if (points.Count == 0)
  992. {
  993. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  994. }
  995.  
  996. var pos = new Vector2I(tempI, tempJ);
  997. if (points.Count > 1 && pos == startPos)
  998. {
  999. polygonData.SetPoints(points.ToArray());
  1000. return polygonData;
  1001. }
  1002.  
  1003. PutUsePoint(new Vector2I(tempI, tempJ));
  1004. tempJ--;
  1005. break;
  1006. }
  1007. else if (IsWayTile(layer, tempI + 1, tempJ)) //向右找
  1008. {
  1009. dir = 0;
  1010.  
  1011. var pos = new Vector2I(tempI, tempJ);
  1012. if (points.Count > 1 && pos == startPos)
  1013. {
  1014. polygonData.SetPoints(points.ToArray());
  1015. return polygonData;
  1016. }
  1017.  
  1018. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  1019. PutUsePoint(pos);
  1020.  
  1021. tempI++;
  1022. break;
  1023. }
  1024.  
  1025. throw new NavigationPointInterleavingException(new Vector2I(tempI, tempJ), "生成导航多边形发生错误! 点: " + new Vector2I(tempI, tempJ) + "发生交错!");
  1026. }
  1027. }
  1028. }
  1029. }
  1030.  
  1031. //计算导航网格内轮廓
  1032. private NavigationPolygonData CalcInline(int layer, int i, int j, Vector2 size)
  1033. {
  1034. var polygonData = new NavigationPolygonData();
  1035. polygonData.Type = NavigationPolygonType.In;
  1036. var points = new List<Vector2>();
  1037. // 0:右, 1:下, 2:左, 3:上
  1038. var dir = 0;
  1039. var offset = new Vector2(size.X * 0.5f, size.Y * 0.5f);
  1040. //找到路, 向右开始找边界
  1041. var startPos = new Vector2I(i - 1, j);
  1042. PutUsePoint(startPos);
  1043.  
  1044. var tempI = i;
  1045. var tempJ = j;
  1046.  
  1047. while (true)
  1048. {
  1049. switch (dir)
  1050. {
  1051. case 0: //右
  1052. {
  1053. if (IsWayTile(layer, tempI, tempJ + 1)) //向下找
  1054. {
  1055. dir = 1;
  1056.  
  1057. var pos = new Vector2I(tempI, tempJ);
  1058. if (points.Count > 1 && pos == startPos)
  1059. {
  1060. polygonData.SetPoints(points.ToArray());
  1061. return polygonData;
  1062. }
  1063.  
  1064. //points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  1065. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y * 2));
  1066. PutUsePoint(pos);
  1067.  
  1068. tempJ++;
  1069. break;
  1070. }
  1071. else if (IsWayTile(layer, tempI + 1, tempJ)) //再向右找
  1072. {
  1073. if (points.Count == 0)
  1074. {
  1075. //points.Add(new Vector2((tempI - 1) * size.X + offset.X, tempJ * size.Y + offset.Y));
  1076. points.Add(new Vector2((tempI - 1) * size.X + offset.X, tempJ * size.Y + offset.Y * 2));
  1077. }
  1078.  
  1079. var pos = new Vector2I(tempI, tempJ);
  1080. if (points.Count > 1 && pos == startPos)
  1081. {
  1082. polygonData.SetPoints(points.ToArray());
  1083. return polygonData;
  1084. }
  1085.  
  1086. PutUsePoint(new Vector2I(tempI, tempJ));
  1087. tempI++;
  1088. break;
  1089. }
  1090. else if (IsWayTile(layer, tempI, tempJ - 1)) //先向上找
  1091. {
  1092. dir = 3;
  1093.  
  1094. var pos = new Vector2I(tempI, tempJ);
  1095. if (points.Count > 1 && pos == startPos)
  1096. {
  1097. polygonData.SetPoints(points.ToArray());
  1098. return polygonData;
  1099. }
  1100.  
  1101. //points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  1102. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y * 2));
  1103. PutUsePoint(pos);
  1104.  
  1105. tempJ--;
  1106. break;
  1107. }
  1108.  
  1109. throw new NavigationPointInterleavingException(new Vector2I(tempI, tempJ), "生成导航多边形发生错误! 点: " + new Vector2I(tempI, tempJ) + "发生交错!");
  1110. }
  1111. case 1: //下
  1112. {
  1113. if (IsWayTile(layer, tempI - 1, tempJ)) //向左找
  1114. {
  1115. dir = 2;
  1116.  
  1117. var pos = new Vector2I(tempI, tempJ);
  1118. if (points.Count > 1 && pos == startPos)
  1119. {
  1120. polygonData.SetPoints(points.ToArray());
  1121. return polygonData;
  1122. }
  1123.  
  1124. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  1125. PutUsePoint(pos);
  1126.  
  1127. tempI--;
  1128. break;
  1129. }
  1130. else if (IsWayTile(layer, tempI, tempJ + 1)) //再向下找
  1131. {
  1132. if (points.Count == 0)
  1133. {
  1134. points.Add(new Vector2((tempI - 1) * size.X + offset.X, tempJ * size.Y + offset.Y));
  1135. }
  1136.  
  1137. var pos = new Vector2I(tempI, tempJ);
  1138. if (points.Count > 1 && pos == startPos)
  1139. {
  1140. polygonData.SetPoints(points.ToArray());
  1141. return polygonData;
  1142. }
  1143.  
  1144. PutUsePoint(new Vector2I(tempI, tempJ));
  1145. tempJ++;
  1146. break;
  1147. }
  1148. else if (IsWayTile(layer, tempI + 1, tempJ)) //先向右找
  1149. {
  1150. dir = 0;
  1151.  
  1152. var pos = new Vector2I(tempI, tempJ);
  1153. if (points.Count > 1 && pos == startPos)
  1154. {
  1155. polygonData.SetPoints(points.ToArray());
  1156. return polygonData;
  1157. }
  1158.  
  1159. //points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  1160. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y * 2));
  1161. PutUsePoint(pos);
  1162.  
  1163. tempI++;
  1164. break;
  1165. }
  1166.  
  1167. throw new NavigationPointInterleavingException(new Vector2I(tempI, tempJ), "生成导航多边形发生错误! 点: " + new Vector2I(tempI, tempJ) + "发生交错!");
  1168. }
  1169. case 2: //左
  1170. {
  1171. if (IsWayTile(layer, tempI, tempJ - 1)) //向上找
  1172. {
  1173. dir = 3;
  1174.  
  1175. var pos = new Vector2I(tempI, tempJ);
  1176. if (points.Count > 1 && pos == startPos)
  1177. {
  1178. polygonData.SetPoints(points.ToArray());
  1179. return polygonData;
  1180. }
  1181.  
  1182. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  1183. PutUsePoint(pos);
  1184.  
  1185. tempJ--;
  1186. break;
  1187. }
  1188. else if (IsWayTile(layer, tempI - 1, tempJ)) //再向左找
  1189. {
  1190. if (points.Count == 0)
  1191. {
  1192. points.Add(new Vector2((tempI - 1) * size.X + offset.X, tempJ * size.Y + offset.Y));
  1193. }
  1194.  
  1195. var pos = new Vector2I(tempI, tempJ);
  1196. if (points.Count > 1 && pos == startPos)
  1197. {
  1198. polygonData.SetPoints(points.ToArray());
  1199. return polygonData;
  1200. }
  1201.  
  1202. PutUsePoint(new Vector2I(tempI, tempJ));
  1203. tempI--;
  1204. break;
  1205. }
  1206. else if (IsWayTile(layer, tempI, tempJ + 1)) //先向下找
  1207. {
  1208. dir = 1;
  1209.  
  1210. var pos = new Vector2I(tempI, tempJ);
  1211. if (points.Count > 1 && pos == startPos)
  1212. {
  1213. polygonData.SetPoints(points.ToArray());
  1214. return polygonData;
  1215. }
  1216.  
  1217. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  1218. PutUsePoint(pos);
  1219.  
  1220. tempJ++;
  1221. break;
  1222. }
  1223.  
  1224. throw new NavigationPointInterleavingException(new Vector2I(tempI, tempJ), "生成导航多边形发生错误! 点: " + new Vector2I(tempI, tempJ) + "发生交错!");
  1225. }
  1226. case 3: //上
  1227. {
  1228. if (IsWayTile(layer, tempI + 1, tempJ)) //向右找
  1229. {
  1230. dir = 0;
  1231.  
  1232. var pos = new Vector2I(tempI, tempJ);
  1233. if (points.Count > 1 && pos == startPos)
  1234. {
  1235. polygonData.SetPoints(points.ToArray());
  1236. return polygonData;
  1237. }
  1238.  
  1239. //points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  1240. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y * 2));
  1241. PutUsePoint(pos);
  1242.  
  1243. tempI++;
  1244. break;
  1245. }
  1246. else if (IsWayTile(layer, tempI, tempJ - 1)) //再向上找
  1247. {
  1248. if (points.Count == 0)
  1249. {
  1250. points.Add(new Vector2((tempI - 1) * size.X + offset.X, tempJ * size.Y + offset.Y));
  1251. }
  1252.  
  1253. var pos = new Vector2I(tempI, tempJ);
  1254. if (points.Count > 1 && pos == startPos)
  1255. {
  1256. polygonData.SetPoints(points.ToArray());
  1257. return polygonData;
  1258. }
  1259.  
  1260. PutUsePoint(new Vector2I(tempI, tempJ));
  1261. tempJ--;
  1262. break;
  1263. }
  1264. else if (IsWayTile(layer, tempI - 1, tempJ)) //先向左找
  1265. {
  1266. dir = 2;
  1267.  
  1268. var pos = new Vector2I(tempI, tempJ);
  1269. if (points.Count > 1 && pos == startPos)
  1270. {
  1271. polygonData.SetPoints(points.ToArray());
  1272. return polygonData;
  1273. }
  1274.  
  1275. points.Add(new Vector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y));
  1276. PutUsePoint(pos);
  1277.  
  1278. tempI--;
  1279. break;
  1280. }
  1281.  
  1282. throw new NavigationPointInterleavingException(new Vector2I(tempI, tempJ), "生成导航多边形发生错误! 点: " + new Vector2I(tempI, tempJ) + "发生交错!");
  1283. }
  1284. }
  1285. }
  1286. }
  1287.  
  1288. //记录导航网格中已经使用过的坐标
  1289. private void PutUsePoint(Vector2I pos)
  1290. {
  1291. if (_usePoints.Contains(pos))
  1292. {
  1293. throw new NavigationPointInterleavingException(pos, "生成导航多边形发生错误! 点: " + pos + "发生交错!");
  1294. }
  1295.  
  1296. _usePoints.Add(pos);
  1297. }
  1298. }