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