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