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