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