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