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