Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / TileMapUtils.cs
@小李xl 小李xl on 18 Feb 2024 9 KB 2格高墙壁, 开发中
  1.  
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Godot;
  5. using Godot.Collections;
  6.  
  7. public static class TileMapUtils
  8. {
  9. public const int MainSource = 0;
  10. public const int MainTerrainSet = 0;
  11. public const int MainTerrain = 0;
  12. /// <summary>
  13. /// 生成自动图块和地形, 并烘焙好导航网格
  14. /// </summary>
  15. public static Rect2I GenerateTerrain(TileMap tileMap, NavigationRegion2D navigationRegion, AutoTileConfig autoTileConfig)
  16. {
  17. var list = new List<Vector2I>();
  18. var xStart = int.MaxValue;
  19. var yStart = int.MaxValue;
  20. var xEnd = int.MinValue;
  21. var yEnd = int.MinValue;
  22.  
  23. var temp = tileMap.GetUsedCells(MapLayer.AutoFloorLayer);
  24. var autoCellLayerGrid = temp.ToHashSet();
  25. foreach (var (x, y) in autoCellLayerGrid)
  26. {
  27. //计算范围
  28. if (x < xStart)
  29. xStart = x;
  30. else if (x > xEnd)
  31. xEnd = x;
  32.  
  33. if (y < yStart)
  34. yStart = y;
  35. else if (y > yEnd)
  36. yEnd = y;
  37. //填充墙壁
  38. if (!autoCellLayerGrid.Contains(new Vector2I(x, y - 1)))
  39. {
  40. var left = autoCellLayerGrid.Contains(new Vector2I(x - 1, y - 1));
  41. var right = autoCellLayerGrid.Contains(new Vector2I(x + 1, y - 1));
  42. if (left && right)
  43. {
  44. var tileCellData1 = autoTileConfig.Wall_Vertical_SingleTop;
  45. tileMap.SetCell(MapLayer.AutoFloorLayer, new Vector2I(x, y - 2), tileCellData1.SourceId, tileCellData1.AutoTileCoords);
  46. var tileCellData2 = autoTileConfig.Wall_Vertical_SingleBottom;
  47. tileMap.SetCell(MapLayer.AutoFloorLayer, new Vector2I(x, y - 1), tileCellData2.SourceId, tileCellData2.AutoTileCoords);
  48. }
  49. else if (left)
  50. {
  51. var tileCellData1 = autoTileConfig.Wall_Vertical_LeftTop;
  52. tileMap.SetCell(MapLayer.AutoFloorLayer, new Vector2I(x, y - 2), tileCellData1.SourceId, tileCellData1.AutoTileCoords);
  53. var tileCellData2 = autoTileConfig.Wall_Vertical_LeftBottom;
  54. tileMap.SetCell(MapLayer.AutoFloorLayer, new Vector2I(x, y - 1), tileCellData2.SourceId, tileCellData2.AutoTileCoords);
  55. }
  56. else if (right)
  57. {
  58. var tileCellData1 = autoTileConfig.Wall_Vertical_RightTop;
  59. tileMap.SetCell(MapLayer.AutoFloorLayer, new Vector2I(x, y - 2), tileCellData1.SourceId, tileCellData1.AutoTileCoords);
  60. var tileCellData2 = autoTileConfig.Wall_Vertical_RightBottom;
  61. tileMap.SetCell(MapLayer.AutoFloorLayer, new Vector2I(x, y - 1), tileCellData2.SourceId, tileCellData2.AutoTileCoords);
  62. }
  63. else
  64. {
  65. var tileCellData1 = autoTileConfig.Wall_Vertical_CenterTop;
  66. tileMap.SetCell(MapLayer.AutoFloorLayer, new Vector2I(x, y - 2), tileCellData1.SourceId, tileCellData1.AutoTileCoords);
  67. var tileCellData2 = autoTileConfig.Wall_Vertical_CenterBottom;
  68. tileMap.SetCell(MapLayer.AutoFloorLayer, new Vector2I(x, y - 1), tileCellData2.SourceId, tileCellData2.AutoTileCoords);
  69. }
  70. }
  71. }
  72. //绘制临时边界
  73. var temp1 = new List<Vector2I>();
  74. for (var x = xStart - 3; x <= xEnd + 3; x++)
  75. {
  76. var p1 = new Vector2I(x, yStart - 5);
  77. var p2 = new Vector2I(x, yEnd + 3);
  78. temp1.Add(p1);
  79. temp1.Add(p2);
  80. //上横
  81. tileMap.SetCell(MapLayer.AutoFloorLayer, p1, autoTileConfig.TopMask.SourceId, autoTileConfig.TopMask.AutoTileCoords);
  82. //下横
  83. tileMap.SetCell(MapLayer.AutoFloorLayer, p2, autoTileConfig.TopMask.SourceId, autoTileConfig.TopMask.AutoTileCoords);
  84. }
  85. for (var y = yStart - 5; y <= yEnd + 3; y++)
  86. {
  87. var p1 = new Vector2I(xStart - 3, y);
  88. var p2 = new Vector2I(xEnd + 3, y);
  89. temp1.Add(p1);
  90. temp1.Add(p2);
  91. //左竖
  92. tileMap.SetCell(MapLayer.AutoFloorLayer, p1, autoTileConfig.TopMask.SourceId, autoTileConfig.TopMask.AutoTileCoords);
  93. //右竖
  94. tileMap.SetCell(MapLayer.AutoFloorLayer, p2, autoTileConfig.TopMask.SourceId, autoTileConfig.TopMask.AutoTileCoords);
  95. }
  96. //计算需要绘制的图块
  97. var temp2 = new List<Vector2I>();
  98. for (var x = xStart - 2; x <= xEnd + 2; x++)
  99. {
  100. for (var y = yStart - 4; y <= yEnd + 2; y++)
  101. {
  102. if (!autoCellLayerGrid.Contains(new Vector2I(x, y)) && !autoCellLayerGrid.Contains(new Vector2I(x, y + 1)) && !autoCellLayerGrid.Contains(new Vector2I(x, y + 2)))
  103. {
  104. list.Add(new Vector2I(x, y));
  105. if (!IsMaskCollisionGround(autoCellLayerGrid, x, y))
  106. {
  107. temp2.Add(new Vector2I(x, y));
  108. }
  109. }
  110. }
  111. }
  112. var arr = new Array<Vector2I>(list);
  113. //绘制自动图块
  114. tileMap.SetCellsTerrainConnect(MapLayer.AutoFloorLayer, arr, MainTerrainSet, MainTerrain, false);
  115. //擦除临时边界
  116. for (var i = 0; i < temp1.Count; i++)
  117. {
  118. tileMap.EraseCell(MapLayer.AutoFloorLayer, temp1[i]);
  119. }
  120.  
  121. //计算区域
  122. var rect = Utils.CalcRect(autoCellLayerGrid);
  123. rect.Position -= new Vector2I(2, 3);
  124. rect.Size += new Vector2I(4, 5);
  125. //开始绘制导航网格
  126. GenerateNavigation(navigationRegion, rect.Position, rect.Size);
  127.  
  128. //擦除临时边界2
  129. for (var i = 0; i < temp2.Count; i++)
  130. {
  131. tileMap.EraseCell(MapLayer.AutoFloorLayer, temp2[i]);
  132. }
  133. //将墙壁移动到指定层
  134. MoveTerrainCell(tileMap, autoTileConfig, autoCellLayerGrid, rect.Position, rect.Size);
  135. return rect;
  136. }
  137. private static bool IsMaskCollisionGround(HashSet<Vector2I> autoCellLayerGrid, int x, int y)
  138. {
  139. for (var i = -2; i <= 2; i++)
  140. {
  141. for (var j = -2; j <= 4; j++)
  142. {
  143. if (autoCellLayerGrid.Contains(new Vector2I(x + i, y + j)))
  144. {
  145. return true;
  146. }
  147. }
  148. }
  149.  
  150. return false;
  151. }
  152. //生成导航网格
  153. private static void GenerateNavigation(NavigationRegion2D navigationRegion, Vector2I currRoomPosition, Vector2I currRoomSize)
  154. {
  155. var navigationPolygon = navigationRegion.NavigationPolygon;
  156. if (navigationPolygon != null)
  157. {
  158. navigationPolygon.Clear();
  159. navigationPolygon.ClearPolygons();
  160. navigationPolygon.ClearOutlines();
  161. }
  162. else
  163. {
  164. navigationPolygon = ResourceManager.Load<NavigationPolygon>(ResourcePath.resource_navigation_NavigationPolygon_tres);
  165. navigationRegion.NavigationPolygon = navigationPolygon;
  166. }
  167.  
  168. var endPos = currRoomPosition + currRoomSize;
  169. navigationPolygon.AddOutline(new []
  170. {
  171. currRoomPosition * GameConfig.TileCellSize,
  172. new Vector2(endPos.X, currRoomPosition.Y) * GameConfig.TileCellSize,
  173. endPos * GameConfig.TileCellSize,
  174. new Vector2(currRoomPosition.X, endPos.Y) * GameConfig.TileCellSize
  175. });
  176. navigationRegion.BakeNavigationPolygon(false);
  177. }
  178. //将自动生成的图块从 MapLayer.AutoFloorLayer 移动到指定图层中
  179. private static void MoveTerrainCell(TileMap tileMap, AutoTileConfig autoTileConfig, HashSet<Vector2I> autoCellLayerGrid, Vector2I currRoomPosition, Vector2I currRoomSize)
  180. {
  181. tileMap.ClearLayer(MapLayer.AutoTopLayer);
  182. tileMap.ClearLayer(MapLayer.AutoMiddleLayer);
  183. var x = currRoomPosition.X;
  184. var y = currRoomPosition.Y - 1;
  185. var w = currRoomSize.X;
  186. var h = currRoomSize.Y + 1;
  187.  
  188. for (var i = 0; i < w; i++)
  189. {
  190. for (var j = 0; j < h; j++)
  191. {
  192. var pos = new Vector2I(x + i, y + j);
  193. if (!autoCellLayerGrid.Contains(pos) && tileMap.GetCellSourceId(MapLayer.AutoFloorLayer, pos) != -1)
  194. {
  195. var atlasCoords = tileMap.GetCellAtlasCoords(MapLayer.AutoFloorLayer, pos);
  196. var layer = autoTileConfig.GetLayer(atlasCoords);
  197. if (layer == MapLayer.AutoMiddleLayer)
  198. {
  199. layer = MapLayer.AutoMiddleLayer;
  200. }
  201. else if (layer == MapLayer.AutoTopLayer)
  202. {
  203. layer = MapLayer.AutoTopLayer;
  204. }
  205. else
  206. {
  207. Debug.LogError($"异常图块: {pos}, 这个图块的图集坐标'{atlasCoords}'不属于'MiddleMapLayer'和'TopMapLayer'!");
  208. continue;
  209. }
  210. tileMap.EraseCell(MapLayer.AutoFloorLayer, pos);
  211. tileMap.SetCell(layer, pos, MainSource, atlasCoords);
  212. }
  213. }
  214. }
  215. }
  216. }