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