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