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