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