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