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