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