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