Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / ui / mapEditor / TileView / EditorTileMap.cs
@小李xl 小李xl on 19 Aug 2023 30 KB 创建房间标记, 开发中
  1. using System.Collections.Generic;
  2. using System.IO;
  3. using System.Text.Json;
  4. using Godot;
  5. using Godot.Collections;
  6. using UI.MapEditorTools;
  7.  
  8. namespace UI.MapEditor;
  9.  
  10. public partial class EditorTileMap : TileMap
  11. {
  12. public enum MouseButtonType
  13. {
  14. /// <summary>
  15. /// 无状态
  16. /// </summary>
  17. None,
  18. /// <summary>
  19. /// 拖拽模式
  20. /// </summary>
  21. Drag,
  22. /// <summary>
  23. /// 笔
  24. /// </summary>
  25. Pen,
  26. /// <summary>
  27. /// 绘制区域模式
  28. /// </summary>
  29. Area,
  30. /// <summary>
  31. /// 编辑工具模式
  32. /// </summary>
  33. Edit,
  34. }
  35. /// <summary>
  36. /// 自动图块地板层
  37. /// </summary>
  38. public const int AutoFloorLayer = 0;
  39. /// <summary>
  40. /// 自定义图块地板层
  41. /// </summary>
  42. public const int CustomFloorLayer = 1;
  43. /// <summary>
  44. /// 自动图块中间层
  45. /// </summary>
  46. public const int AutoMiddleLayer = 2;
  47. /// <summary>
  48. /// 自定义图块中间层
  49. /// </summary>
  50. public const int CustomMiddleLayer = 3;
  51. /// <summary>
  52. /// 自动图块顶层
  53. /// </summary>
  54. public const int AutoTopLayer = 4;
  55. /// <summary>
  56. /// 自定义图块顶层
  57. /// </summary>
  58. public const int CustomTopLayer = 5;
  59. /// <summary>
  60. /// 所属地图编辑器UI
  61. /// </summary>
  62. public MapEditorPanel MapEditorPanel { get; set; }
  63. /// <summary>
  64. /// 编辑器工具UI
  65. /// </summary>
  66. public MapEditorToolsPanel MapEditorToolsPanel { get; set; }
  67. /// <summary>
  68. /// 左键功能
  69. /// </summary>
  70. public MouseButtonType MouseType { get; private set; } = MouseButtonType.Pen;
  71. //鼠标坐标
  72. private Vector2 _mousePosition;
  73. //鼠标所在的cell坐标
  74. private Vector2I _mouseCellPosition;
  75. //上一帧鼠标所在的cell坐标
  76. private Vector2I _prevMouseCellPosition = new Vector2I(-99999, -99999);
  77. //单次绘制是否改变过tile数据
  78. private bool _changeFlag = false;
  79. //左键开始按下时鼠标所在的坐标
  80. private Vector2I _mouseStartCellPosition;
  81. //鼠标中建是否按下
  82. private bool _isMiddlePressed = false;
  83. private Vector2 _moveOffset;
  84. //左键是否按下
  85. private bool _isLeftPressed = false;
  86. //右键是否按下
  87. private bool _isRightPressed = false;
  88. //绘制填充区域
  89. private bool _drawFullRect = false;
  90. //负责存储自动图块数据
  91. private Grid<bool> _autoCellLayerGrid = new Grid<bool>();
  92. //用于生成导航网格
  93. private DungeonTileMap _dungeonTileMap;
  94. //停止绘制多久后开始执行生成操作
  95. private float _generateInterval = 3f;
  96. //生成自动图块和导航网格的计时器
  97. private float _generateTimer = -1;
  98. //检测地形结果
  99. private bool _checkTerrainFlag = true;
  100. //错误地形位置
  101. private Vector2I _checkTerrainErrorPosition = Vector2I.Zero;
  102. //是否执行生成地形成功
  103. private bool _isGenerateTerrain = false;
  104. private bool _initLayer = false;
  105.  
  106. //--------- 配置数据 -------------
  107. private int _sourceId = 0;
  108. private int _terrainSet = 0;
  109. private int _terrain = 0;
  110. private AutoTileConfig _autoTileConfig = new AutoTileConfig();
  111. /// <summary>
  112. /// 正在编辑的房间数据
  113. /// </summary>
  114. public DungeonRoomSplit RoomSplit { get; private set; }
  115. /// <summary>
  116. /// 波数网格选中的索引
  117. /// </summary>
  118. public int SelectWaveIndex { get; set; } = -1;
  119.  
  120. /// <summary>
  121. /// 选中的预设
  122. /// </summary>
  123. public int SelectPreinstallIndex
  124. {
  125. get => _selectPreinstallIndex;
  126. set
  127. {
  128. if (_selectPreinstallIndex != value)
  129. {
  130. _selectPreinstallIndex = value;
  131. EventManager.EmitEvent(EventEnum.OnSelectPreinstall);
  132. }
  133. }
  134. }
  135.  
  136. private int _selectPreinstallIndex = -1;
  137.  
  138. /// <summary>
  139. /// 当前选中的预设
  140. /// </summary>
  141. public RoomPreinstall SelectPreinstall
  142. {
  143. get
  144. {
  145. if (SelectPreinstallIndex == -1 || SelectPreinstallIndex >= RoomSplit.Preinstall.Count)
  146. {
  147. return null;
  148. }
  149.  
  150. return RoomSplit.Preinstall[SelectPreinstallIndex];
  151. }
  152. }
  153.  
  154. /// <summary>
  155. /// 选中的标记
  156. /// </summary>
  157. public MarkTool SelectMark => MapEditorToolsPanel.ActiveMark;
  158.  
  159. //变动过的数据
  160. //地图位置, 单位: 格
  161. private Vector2I _roomPosition;
  162. //地图大小, 单位: 格
  163. private Vector2I _roomSize;
  164. private List<DoorAreaInfo> _doorConfigs = new List<DoorAreaInfo>();
  165. //-------------------------------
  166.  
  167. public override void _Ready()
  168. {
  169. InitLayer();
  170. }
  171.  
  172. public override void _Process(double delta)
  173. {
  174. var newDelta = (float)delta;
  175. _drawFullRect = false;
  176. var position = GetLocalMousePosition();
  177. _mouseCellPosition = LocalToMap(position);
  178. _mousePosition = new Vector2(
  179. _mouseCellPosition.X * GameConfig.TileCellSize,
  180. _mouseCellPosition.Y * GameConfig.TileCellSize
  181. );
  182. if (!MapEditorToolsPanel.S_HBoxContainer.Instance.IsPositionOver(GetGlobalMousePosition())) //不在Ui节点上
  183. {
  184. //左键绘制
  185. if (_isLeftPressed)
  186. {
  187. if (MouseType == MouseButtonType.Pen) //绘制单格
  188. {
  189. if (_prevMouseCellPosition != _mouseCellPosition || !_changeFlag) //鼠标位置变过
  190. {
  191. _changeFlag = true;
  192. _prevMouseCellPosition = _mouseCellPosition;
  193. //绘制自动图块
  194. SetSingleAutoCell(_mouseCellPosition);
  195. }
  196. }
  197. else if (MouseType == MouseButtonType.Area) //绘制区域
  198. {
  199. _drawFullRect = true;
  200. }
  201. else if (MouseType == MouseButtonType.Drag) //拖拽
  202. {
  203. SetMapPosition(GetGlobalMousePosition() + _moveOffset);
  204. }
  205. }
  206. else if (_isRightPressed) //右键擦除
  207. {
  208. if (MouseType == MouseButtonType.Pen) //绘制单格
  209. {
  210. if (_prevMouseCellPosition != _mouseCellPosition || !_changeFlag) //鼠标位置变过
  211. {
  212. _changeFlag = true;
  213. _prevMouseCellPosition = _mouseCellPosition;
  214. EraseSingleAutoCell(_mouseCellPosition);
  215. }
  216. }
  217. else if (MouseType == MouseButtonType.Area) //绘制区域
  218. {
  219. _drawFullRect = true;
  220. }
  221. else if (MouseType == MouseButtonType.Drag) //拖拽
  222. {
  223. SetMapPosition(GetGlobalMousePosition() + _moveOffset);
  224. }
  225. }
  226. else if (_isMiddlePressed) //中键移动
  227. {
  228. SetMapPosition(GetGlobalMousePosition() + _moveOffset);
  229. }
  230. }
  231.  
  232. //绘制停止指定时间后, 生成导航网格
  233. if (_generateTimer > 0)
  234. {
  235. _generateTimer -= newDelta;
  236. if (_generateTimer <= 0)
  237. {
  238. //计算区域
  239. CalcTileRect(false);
  240. GD.Print("开始检测是否可以生成地形...");
  241. if (CheckTerrain())
  242. {
  243. GD.Print("开始绘制导航网格...");
  244. if (GenerateNavigation())
  245. {
  246. GD.Print("开始绘制自动贴图...");
  247. GenerateTerrain();
  248. _isGenerateTerrain = true;
  249. }
  250. }
  251. else
  252. {
  253. SetErrorCell(_checkTerrainErrorPosition);
  254. }
  255. }
  256. }
  257. }
  258.  
  259. /// <summary>
  260. /// 绘制辅助线
  261. /// </summary>
  262. public void DrawGuides(CanvasItem canvasItem)
  263. {
  264. //轴线
  265. canvasItem.DrawLine(new Vector2(0, 2000), new Vector2(0, -2000), Colors.Green);
  266. canvasItem.DrawLine(new Vector2(2000, 0), new Vector2( -2000, 0), Colors.Red);
  267. //绘制房间区域
  268. if (_roomSize.X != 0 && _roomSize.Y != 0)
  269. {
  270. var size = TileSet.TileSize;
  271. canvasItem.DrawRect(new Rect2(_roomPosition * size, _roomSize * size),
  272. Colors.Aqua, false, 5f / Scale.X);
  273. }
  274. if (_checkTerrainFlag) //已经通过地形检测
  275. {
  276. //绘制导航网格
  277. var result = _dungeonTileMap.GetGenerateNavigationResult();
  278. if (result != null && result.Success)
  279. {
  280. var polygonData = _dungeonTileMap.GetPolygonData();
  281. Utils.DrawNavigationPolygon(canvasItem, polygonData, 3f / Scale.X);
  282. }
  283. }
  284.  
  285. if (MouseType == MouseButtonType.Pen || MouseType == MouseButtonType.Area)
  286. {
  287. if (_drawFullRect) //绘制填充矩形
  288. {
  289. var size = TileSet.TileSize;
  290. var cellPos = _mouseStartCellPosition;
  291. var temp = size;
  292. if (_mouseStartCellPosition.X > _mouseCellPosition.X)
  293. {
  294. cellPos.X += 1;
  295. temp.X -= size.X;
  296. }
  297. if (_mouseStartCellPosition.Y > _mouseCellPosition.Y)
  298. {
  299. cellPos.Y += 1;
  300. temp.Y -= size.Y;
  301. }
  302.  
  303. var pos = cellPos * size;
  304. canvasItem.DrawRect(new Rect2(pos, _mousePosition - pos + temp), Colors.White, false, 2f / Scale.X);
  305. }
  306. else //绘制单格
  307. {
  308. canvasItem.DrawRect(new Rect2(_mousePosition, TileSet.TileSize), Colors.White, false, 2f / Scale.X);
  309. }
  310. }
  311. }
  312.  
  313. public override void _Input(InputEvent @event)
  314. {
  315. if (@event is InputEventMouseButton mouseButton)
  316. {
  317. if (mouseButton.ButtonIndex == MouseButton.Left) //左键
  318. {
  319. if (mouseButton.Pressed) //按下
  320. {
  321. _moveOffset = Position - GetGlobalMousePosition();
  322. _mouseStartCellPosition = LocalToMap(GetLocalMousePosition());
  323. }
  324. else
  325. {
  326. _changeFlag = false;
  327. if (_drawFullRect) //松开, 提交绘制的矩形区域
  328. {
  329. SetRectAutoCell(_mouseStartCellPosition, _mouseCellPosition);
  330. _drawFullRect = false;
  331. }
  332. }
  333.  
  334. _isLeftPressed = mouseButton.Pressed;
  335. }
  336. else if (mouseButton.ButtonIndex == MouseButton.Right) //右键
  337. {
  338. if (mouseButton.Pressed) //按下
  339. {
  340. _moveOffset = Position - GetGlobalMousePosition();
  341. _mouseStartCellPosition = LocalToMap(GetLocalMousePosition());
  342. }
  343. else
  344. {
  345. _changeFlag = false;
  346. if (_drawFullRect) //松开, 提交擦除的矩形区域
  347. {
  348. EraseRectAutoCell(_mouseStartCellPosition, _mouseCellPosition);
  349. _drawFullRect = false;
  350. }
  351. }
  352. _isRightPressed = mouseButton.Pressed;
  353. }
  354. else if (mouseButton.ButtonIndex == MouseButton.WheelDown)
  355. {
  356. //缩小
  357. Shrink();
  358. }
  359. else if (mouseButton.ButtonIndex == MouseButton.WheelUp)
  360. {
  361. //放大
  362. Magnify();
  363. }
  364. else if (mouseButton.ButtonIndex == MouseButton.Middle)
  365. {
  366. _isMiddlePressed = mouseButton.Pressed;
  367. if (_isMiddlePressed)
  368. {
  369. _moveOffset = Position - GetGlobalMousePosition();
  370. }
  371. }
  372. }
  373. else if (@event is InputEventKey eventKey)
  374. {
  375. if (eventKey.Pressed && eventKey.Keycode == Key.M)
  376. {
  377. GD.Print("保存地牢房间数据...");
  378. TriggerSave();
  379. }
  380. }
  381. }
  382.  
  383. //将指定层数据存入list中
  384. private void PushLayerDataToList(int layer, int sourceId, List<int> list)
  385. {
  386. var layerArray = GetUsedCellsById(layer, sourceId);
  387. foreach (var pos in layerArray)
  388. {
  389. var atlasCoords = GetCellAtlasCoords(layer, pos);
  390. list.Add(pos.X);
  391. list.Add(pos.Y);
  392. list.Add(_sourceId);
  393. list.Add(atlasCoords.X);
  394. list.Add(atlasCoords.Y);
  395. }
  396. }
  397.  
  398. private void SetLayerDataFromList(int layer, List<int> list)
  399. {
  400. for (var i = 0; i < list.Count; i += 5)
  401. {
  402. var pos = new Vector2I(list[i], list[i + 1]);
  403. var sourceId = list[i + 2];
  404. var atlasCoords = new Vector2I(list[i + 3], list[i + 4]);
  405. SetCell(layer, pos, sourceId, atlasCoords);
  406. if (layer == AutoFloorLayer)
  407. {
  408. _autoCellLayerGrid.Set(pos, true);
  409. }
  410. }
  411. }
  412.  
  413. //保存地牢
  414. private void TriggerSave()
  415. {
  416. SaveRoomInfoConfig();
  417. SaveTileInfoConfig();
  418. SavePreinstallConfig();
  419. }
  420.  
  421. /// <summary>
  422. /// 加载地牢, 返回是否加载成功
  423. /// </summary>
  424. public bool Load(DungeonRoomSplit roomSplit)
  425. {
  426. //重新加载数据
  427. roomSplit.ReloadRoomInfo();
  428. roomSplit.ReloadTileInfo();
  429. roomSplit.ReloadPreinstall();
  430. RoomSplit = roomSplit;
  431. var roomInfo = roomSplit.RoomInfo;
  432. var tileInfo = roomSplit.TileInfo;
  433.  
  434. _roomPosition = roomInfo.Position.AsVector2I();
  435. SetMapSize(roomInfo.Size.AsVector2I(), true);
  436. _doorConfigs.Clear();
  437. foreach (var doorAreaInfo in roomInfo.DoorAreaInfos)
  438. {
  439. _doorConfigs.Add(doorAreaInfo.Clone());
  440. }
  441.  
  442. //初始化层级数据
  443. InitLayer();
  444. //地块数据
  445. SetLayerDataFromList(AutoFloorLayer, tileInfo.Floor);
  446. SetLayerDataFromList(AutoMiddleLayer, tileInfo.Middle);
  447. SetLayerDataFromList(AutoTopLayer, tileInfo.Top);
  448. //导航网格数据
  449. _dungeonTileMap.SetPolygonData(tileInfo.NavigationList);
  450.  
  451. //聚焦
  452. //MapEditorPanel.CallDelay(0.1f, OnClickCenterTool);
  453. //CallDeferred(nameof(OnClickCenterTool), null);
  454. //加载门编辑区域
  455. foreach (var doorAreaInfo in _doorConfigs)
  456. {
  457. MapEditorToolsPanel.CreateDoorTool(doorAreaInfo);
  458. }
  459. //聚焦
  460. OnClickCenterTool(null);
  461. return true;
  462. }
  463.  
  464. private void InitLayer()
  465. {
  466. if (_initLayer)
  467. {
  468. return;
  469. }
  470.  
  471. _initLayer = true;
  472. //初始化层级数据
  473. AddLayer(CustomFloorLayer);
  474. SetLayerZIndex(CustomFloorLayer, CustomFloorLayer);
  475. AddLayer(AutoMiddleLayer);
  476. SetLayerZIndex(AutoMiddleLayer, AutoMiddleLayer);
  477. AddLayer(CustomMiddleLayer);
  478. SetLayerZIndex(CustomMiddleLayer, CustomMiddleLayer);
  479. AddLayer(AutoTopLayer);
  480. SetLayerZIndex(AutoTopLayer, AutoTopLayer);
  481. AddLayer(CustomTopLayer);
  482. SetLayerZIndex(CustomTopLayer, CustomTopLayer);
  483.  
  484. _dungeonTileMap = new DungeonTileMap(this);
  485. _dungeonTileMap.SetFloorAtlasCoords(new List<Vector2I>(new []{ _autoTileConfig.Floor.AutoTileCoord }));
  486. }
  487.  
  488. //缩小
  489. private void Shrink()
  490. {
  491. var pos = GetLocalMousePosition();
  492. var scale = Scale / 1.1f;
  493. if (scale.LengthSquared() >= 0.5f)
  494. {
  495. Scale = scale;
  496. SetMapPosition(Position + pos * 0.1f * scale);
  497. }
  498. else
  499. {
  500. GD.Print("太小了");
  501. }
  502. }
  503. //放大
  504. private void Magnify()
  505. {
  506. var pos = GetLocalMousePosition();
  507. var prevScale = Scale;
  508. var scale = prevScale * 1.1f;
  509. if (scale.LengthSquared() <= 2000)
  510. {
  511. Scale = scale;
  512. SetMapPosition(Position - pos * 0.1f * prevScale);
  513. }
  514. else
  515. {
  516. GD.Print("太大了");
  517. }
  518. }
  519.  
  520. //绘制单个自动贴图
  521. private void SetSingleAutoCell(Vector2I position)
  522. {
  523. SetCell(GetFloorLayer(), position, _sourceId, _autoTileConfig.Floor.AutoTileCoord);
  524. if (!_autoCellLayerGrid.Contains(position.X, position.Y))
  525. {
  526. ResetGenerateTimer();
  527. _autoCellLayerGrid.Set(position.X, position.Y, true);
  528. }
  529. }
  530. //绘制区域自动贴图
  531. private void SetRectAutoCell(Vector2I start, Vector2I end)
  532. {
  533. ResetGenerateTimer();
  534. if (start.X > end.X)
  535. {
  536. var temp = end.X;
  537. end.X = start.X;
  538. start.X = temp;
  539. }
  540. if (start.Y > end.Y)
  541. {
  542. var temp = end.Y;
  543. end.Y = start.Y;
  544. start.Y = temp;
  545. }
  546.  
  547. var width = end.X - start.X + 1;
  548. var height = end.Y - start.Y + 1;
  549. for (var i = 0; i < width; i++)
  550. {
  551. for (var j = 0; j < height; j++)
  552. {
  553. SetCell(GetFloorLayer(), new Vector2I(start.X + i, start.Y + j), _sourceId, _autoTileConfig.Floor.AutoTileCoord);
  554. }
  555. }
  556.  
  557. _autoCellLayerGrid.SetRect(start, new Vector2I(width, height), true);
  558. }
  559.  
  560. //擦除单个自动图块
  561. private void EraseSingleAutoCell(Vector2I position)
  562. {
  563. EraseCell(GetFloorLayer(), position);
  564. if (_autoCellLayerGrid.Remove(position.X, position.Y))
  565. {
  566. ResetGenerateTimer();
  567. }
  568. }
  569. //擦除一个区域内的自动贴图
  570. private void EraseRectAutoCell(Vector2I start, Vector2I end)
  571. {
  572. ResetGenerateTimer();
  573. if (start.X > end.X)
  574. {
  575. var temp = end.X;
  576. end.X = start.X;
  577. start.X = temp;
  578. }
  579. if (start.Y > end.Y)
  580. {
  581. var temp = end.Y;
  582. end.Y = start.Y;
  583. start.Y = temp;
  584. }
  585.  
  586. var width = end.X - start.X + 1;
  587. var height = end.Y - start.Y + 1;
  588. for (var i = 0; i < width; i++)
  589. {
  590. for (var j = 0; j < height; j++)
  591. {
  592. EraseCell(GetFloorLayer(), new Vector2I(start.X + i, start.Y + j));
  593. }
  594. }
  595. _autoCellLayerGrid.RemoveRect(start, new Vector2I(width, height));
  596. }
  597.  
  598. //重置计时器
  599. private void ResetGenerateTimer()
  600. {
  601. _generateTimer = _generateInterval;
  602. _isGenerateTerrain = false;
  603. _dungeonTileMap.ClearPolygonData();
  604. ClearLayer(AutoTopLayer);
  605. ClearLayer(AutoMiddleLayer);
  606. }
  607.  
  608. //重新计算房间区域
  609. private void CalcTileRect(bool refreshDoorTrans)
  610. {
  611. var rect = GetUsedRect();
  612. _roomPosition = rect.Position;
  613. SetMapSize(rect.Size, refreshDoorTrans);
  614. }
  615. //检测是否有不合规的图块, 返回true表示图块正常
  616. private bool CheckTerrain()
  617. {
  618. var x = _roomPosition.X;
  619. var y = _roomPosition.Y;
  620. var w = _roomSize.X;
  621. var h = _roomSize.Y;
  622.  
  623. for (var i = 0; i < w; i++)
  624. {
  625. for (var j = 0; j < h; j++)
  626. {
  627. var pos = new Vector2I(x + i, y + j);
  628. if (GetCellSourceId(AutoFloorLayer, pos) == -1)
  629. {
  630. //先检测对边是否有地板
  631. if ((_autoCellLayerGrid.Get(pos.X - 1, pos.Y) && _autoCellLayerGrid.Get(pos.X + 1, pos.Y)) //left & right
  632. || (_autoCellLayerGrid.Get(pos.X, pos.Y + 1) && _autoCellLayerGrid.Get(pos.X, pos.Y - 1))) //top & down
  633. {
  634. _checkTerrainFlag = false;
  635. _checkTerrainErrorPosition = pos;
  636. return false;
  637. }
  638. //再检测对角是否有地板
  639. var topLeft = _autoCellLayerGrid.Get(pos.X - 1, pos.Y + 1); //top-left
  640. var downRight = _autoCellLayerGrid.Get(pos.X + 1, pos.Y - 1); //down-right
  641. var downLeft = _autoCellLayerGrid.Get(pos.X - 1, pos.Y - 1); //down-left
  642. var topRight = _autoCellLayerGrid.Get(pos.X + 1, pos.Y + 1); //top-right
  643. if ((topLeft && downRight && !downLeft && !topRight) || (!topLeft && !downRight && downLeft && topRight))
  644. {
  645. _checkTerrainFlag = false;
  646. _checkTerrainErrorPosition = pos;
  647. return false;
  648. }
  649. }
  650. }
  651. }
  652.  
  653. _checkTerrainFlag = true;
  654. return true;
  655. }
  656. //生成自动图块 (地形)
  657. private void GenerateTerrain()
  658. {
  659. ClearLayer(AutoFloorLayer);
  660. var list = new List<Vector2I>();
  661. _autoCellLayerGrid.ForEach((x, y, data) =>
  662. {
  663. if (data)
  664. {
  665. list.Add(new Vector2I(x, y));
  666. }
  667. });
  668. var arr = new Array<Vector2I>(list);
  669. //绘制自动图块
  670. SetCellsTerrainConnect(AutoFloorLayer, arr, _terrainSet, _terrain, false);
  671. //计算区域
  672. CalcTileRect(true);
  673. //将墙壁移动到指定层
  674. MoveTerrainCell();
  675. }
  676.  
  677. //将自动生成的图块从 AutoFloorLayer 移动到指定图层中
  678. private void MoveTerrainCell()
  679. {
  680. ClearLayer(AutoTopLayer);
  681. ClearLayer(AutoMiddleLayer);
  682. var x = _roomPosition.X;
  683. var y = _roomPosition.Y;
  684. var w = _roomSize.X;
  685. var h = _roomSize.Y;
  686.  
  687. for (var i = 0; i < w; i++)
  688. {
  689. for (var j = 0; j < h; j++)
  690. {
  691. var pos = new Vector2I(x + i, y + j);
  692. if (!_autoCellLayerGrid.Contains(pos) && GetCellSourceId(AutoFloorLayer, pos) != -1)
  693. {
  694. var atlasCoords = GetCellAtlasCoords(AutoFloorLayer, pos);
  695. var layer = _autoTileConfig.GetLayer(atlasCoords);
  696. if (layer == GameConfig.MiddleMapLayer)
  697. {
  698. layer = AutoMiddleLayer;
  699. }
  700. else if (layer == GameConfig.TopMapLayer)
  701. {
  702. layer = AutoTopLayer;
  703. }
  704. else
  705. {
  706. GD.PrintErr($"异常图块: {pos}, 这个图块的图集坐标'{atlasCoords}'不属于'MiddleMapLayer'和'TopMapLayer'!");
  707. continue;
  708. }
  709. EraseCell(AutoFloorLayer, pos);
  710. SetCell(layer, pos, _sourceId, atlasCoords);
  711. }
  712. }
  713. }
  714. }
  715.  
  716. //生成导航网格
  717. private bool GenerateNavigation()
  718. {
  719. _dungeonTileMap.GenerateNavigationPolygon(AutoFloorLayer);
  720. var result = _dungeonTileMap.GetGenerateNavigationResult();
  721. if (result.Success)
  722. {
  723. CloseErrorCell();
  724. }
  725. else
  726. {
  727. SetErrorCell(result.Exception.Point);
  728. }
  729.  
  730. return result.Success;
  731. }
  732.  
  733. //设置显示的错误cell, 会标记上红色的闪烁动画
  734. private void SetErrorCell(Vector2I pos)
  735. {
  736. MapEditorPanel.S_ErrorCell.Instance.Position = pos * CellQuadrantSize;
  737. MapEditorPanel.S_ErrorCellAnimationPlayer.Instance.Play(AnimatorNames.Show);
  738. }
  739.  
  740. //关闭显示的错误cell
  741. private void CloseErrorCell()
  742. {
  743. MapEditorPanel.S_ErrorCellAnimationPlayer.Instance.Stop();
  744. }
  745.  
  746. private int GetFloorLayer()
  747. {
  748. return AutoFloorLayer;
  749. }
  750.  
  751. private int GetMiddleLayer()
  752. {
  753. return AutoMiddleLayer;
  754. }
  755.  
  756. private int GetTopLayer()
  757. {
  758. return AutoTopLayer;
  759. }
  760.  
  761. /// <summary>
  762. /// 选中拖拽功能
  763. /// </summary>
  764. public void OnSelectHandTool(object arg)
  765. {
  766. MouseType = MouseButtonType.Drag;
  767. }
  768. /// <summary>
  769. /// 选中画笔攻击
  770. /// </summary>
  771. public void OnSelectPenTool(object arg)
  772. {
  773. MouseType = MouseButtonType.Pen;
  774. }
  775.  
  776. /// <summary>
  777. /// 选中绘制区域功能
  778. /// </summary>
  779. public void OnSelectRectTool(object arg)
  780. {
  781. MouseType = MouseButtonType.Area;
  782. }
  783.  
  784. /// <summary>
  785. /// 选择编辑门区域
  786. /// </summary>
  787. public void OnSelectEditTool(object arg)
  788. {
  789. MouseType = MouseButtonType.Edit;
  790. }
  791.  
  792. /// <summary>
  793. /// 聚焦
  794. /// </summary>
  795. public void OnClickCenterTool(object arg)
  796. {
  797. var pos = MapEditorPanel.S_SubViewport.Instance.Size / 2;
  798. if (_roomSize.X == 0 && _roomSize.Y == 0) //聚焦原点
  799. {
  800. SetMapPosition(pos);
  801. }
  802. else //聚焦地图中心点
  803. {
  804. SetMapPosition(pos - (_roomPosition + _roomSize / 2) * TileSet.TileSize * Scale);
  805. }
  806. }
  807.  
  808. /// <summary>
  809. /// 创建地牢房间门区域
  810. /// </summary>
  811. /// <param name="direction">门方向</param>
  812. /// <param name="start">起始坐标, 单位: 像素</param>
  813. /// <param name="end">结束坐标, 单位: 像素</param>
  814. public DoorAreaInfo CreateDoorArea(DoorDirection direction, int start, int end)
  815. {
  816. var doorAreaInfo = new DoorAreaInfo();
  817. doorAreaInfo.Direction = direction;
  818. doorAreaInfo.Start = start;
  819. doorAreaInfo.End = end;
  820. //doorAreaInfo.CalcPosition(_roomPosition, _roomSize);
  821. _doorConfigs.Add(doorAreaInfo);
  822. return doorAreaInfo;
  823. }
  824.  
  825. /// <summary>
  826. /// 检测门区域数据是否可以提交
  827. /// </summary>
  828. /// <param name="direction">门方向</param>
  829. /// <param name="start">起始坐标, 单位: 像素</param>
  830. /// <param name="end">结束坐标, 单位: 像素</param>
  831. /// <returns></returns>
  832. public bool CheckDoorArea(DoorDirection direction, int start, int end)
  833. {
  834. foreach (var item in _doorConfigs)
  835. {
  836. if (item.Direction == direction)
  837. {
  838. if (CheckValueCollision(item.Start, item.End, start, end))
  839. {
  840. return false;
  841. }
  842. }
  843. }
  844.  
  845. return true;
  846. }
  847. /// <summary>
  848. /// 检测门区域数据是否可以提交
  849. /// </summary>
  850. /// <param name="target">需要检测的门</param>
  851. /// <param name="start">起始坐标, 单位: 像素</param>
  852. /// <param name="end">结束坐标, 单位: 像素</param>
  853. public bool CheckDoorArea(DoorAreaInfo target, int start, int end)
  854. {
  855. foreach (var item in _doorConfigs)
  856. {
  857. if (item.Direction == target.Direction && item != target)
  858. {
  859. if (CheckValueCollision(item.Start, item.End, start, end))
  860. {
  861. return false;
  862. }
  863. }
  864. }
  865.  
  866. return true;
  867. }
  868. private bool CheckValueCollision(float o1, float o2, float h1, float h2)
  869. {
  870. var size = GameConfig.TileCellSize;
  871. return !(h2 < o1 - 3 * size || o2 + 3 * size < h1);
  872. }
  873.  
  874. /// <summary>
  875. /// 移除门区域数据
  876. /// </summary>
  877. public void RemoveDoorArea(DoorAreaInfo doorAreaInfo)
  878. {
  879. _doorConfigs.Remove(doorAreaInfo);
  880. }
  881. //保存房间配置
  882. private void SaveRoomInfoConfig()
  883. {
  884. //存入本地
  885. var roomInfo = RoomSplit.RoomInfo;
  886. var path = MapProjectManager.GetConfigPath(roomInfo.GroupName,roomInfo.RoomType, roomInfo.RoomName);
  887. if (!Directory.Exists(path))
  888. {
  889. Directory.CreateDirectory(path);
  890. }
  891. roomInfo.Position = new SerializeVector2(_roomPosition);
  892. roomInfo.Size = new SerializeVector2(_roomSize);
  893. roomInfo.DoorAreaInfos.Clear();
  894. roomInfo.DoorAreaInfos.AddRange(_doorConfigs);
  895.  
  896. path += "/" + MapProjectManager.GetRoomInfoConfigName(roomInfo.RoomName);
  897. var jsonStr = JsonSerializer.Serialize(roomInfo);
  898. File.WriteAllText(path, jsonStr);
  899. }
  900.  
  901. //保存地块数据
  902. public void SaveTileInfoConfig()
  903. {
  904. //存入本地
  905. var roomInfo = RoomSplit.RoomInfo;
  906. var path = MapProjectManager.GetConfigPath(roomInfo.GroupName,roomInfo.RoomType, roomInfo.RoomName);
  907. if (!Directory.Exists(path))
  908. {
  909. Directory.CreateDirectory(path);
  910. }
  911.  
  912. var tileInfo = RoomSplit.TileInfo;
  913. tileInfo.NavigationList.Clear();
  914. tileInfo.NavigationList.AddRange(_dungeonTileMap.GetPolygonData());
  915. tileInfo.Floor.Clear();
  916. tileInfo.Middle.Clear();
  917. tileInfo.Top.Clear();
  918.  
  919. PushLayerDataToList(AutoFloorLayer, _sourceId, tileInfo.Floor);
  920. PushLayerDataToList(AutoMiddleLayer, _sourceId, tileInfo.Middle);
  921. PushLayerDataToList(AutoTopLayer, _sourceId, tileInfo.Top);
  922. path += "/" + MapProjectManager.GetTileInfoConfigName(roomInfo.RoomName);
  923. var jsonStr = JsonSerializer.Serialize(tileInfo);
  924. File.WriteAllText(path, jsonStr);
  925. }
  926.  
  927. //保存预设数据
  928. public void SavePreinstallConfig()
  929. {
  930. //存入本地
  931. var roomInfo = RoomSplit.RoomInfo;
  932. var path = MapProjectManager.GetConfigPath(roomInfo.GroupName,roomInfo.RoomType, roomInfo.RoomName);
  933. if (!Directory.Exists(path))
  934. {
  935. Directory.CreateDirectory(path);
  936. }
  937.  
  938. path += "/" + MapProjectManager.GetRoomPreinstallConfigName(roomInfo.RoomName);
  939. var jsonStr = JsonSerializer.Serialize(RoomSplit.Preinstall);
  940. File.WriteAllText(path, jsonStr);
  941. }
  942.  
  943. //设置地图坐标
  944. private void SetMapPosition(Vector2 pos)
  945. {
  946. Position = pos;
  947. MapEditorToolsPanel.SetToolTransform(pos, Scale);
  948. }
  949.  
  950. //设置地图大小
  951. private void SetMapSize(Vector2I size, bool refreshDoorTrans)
  952. {
  953. if (_roomSize != size)
  954. {
  955. _roomSize = size;
  956.  
  957. if (refreshDoorTrans)
  958. {
  959. MapEditorToolsPanel.SetDoorHoverToolTransform(_roomPosition, _roomSize);
  960. }
  961. }
  962. }
  963. }