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