Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / ui / mapEditor / tileView / EditorTileMap.cs
@小李xl 小李xl on 27 Dec 2023 41 KB 地牢新版地形开发中
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  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; private 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 InfiniteGrid<bool> _autoCellLayerGrid = new InfiniteGrid<bool>();
  96. //停止绘制多久后开始执行生成操作
  97. private float _generateInterval = 3f;
  98. //生成自动图块和导航网格的计时器
  99. private float _generateTimer = -1;
  100. //检测地形结果
  101. private bool _checkTerrainFlag = true;
  102. //错误地形位置
  103. private Vector2I _checkTerrainErrorPosition = Vector2I.Zero;
  104. //是否执行生成地形成功
  105. private bool _isGenerateTerrain = true;
  106. //导航网格数据
  107. private Vector2[][] _polygonData;
  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;
  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. /// <summary>
  147. /// 初始化图块集。
  148. /// </summary>
  149. /// <param name="tileSet">要初始化的图块集</param>
  150. public void InitTileSet(TileSet tileSet)
  151. {
  152. TileSet = tileSet;
  153.  
  154. // 创建AutoTileConfig对象
  155. // 使用第一个图块集源作为参数
  156. _autoTileConfig = new AutoTileConfig(0, tileSet.GetSource(0) as TileSetAtlasSource);
  157. }
  158. public void SetUiNode(IUiNode uiNode)
  159. {
  160. _editorTileMap = (MapEditor.TileMap)uiNode;
  161. MapEditorPanel = _editorTileMap.UiPanel;
  162. MapEditorToolsPanel = _editorTileMap.UiPanel.S_MapEditorTools.Instance;
  163.  
  164. _editorTileMap.L_Brush.Instance.Draw += DrawGuides;
  165. _eventFactory = EventManager.CreateEventFactory();
  166. _eventFactory.AddEventListener(EventEnum.OnSelectDragTool, OnSelectHandTool);
  167. _eventFactory.AddEventListener(EventEnum.OnSelectPenTool, OnSelectPenTool);
  168. _eventFactory.AddEventListener(EventEnum.OnSelectRectTool, OnSelectRectTool);
  169. _eventFactory.AddEventListener(EventEnum.OnSelectEditTool, OnSelectEditTool);
  170. _eventFactory.AddEventListener(EventEnum.OnClickCenterTool, OnClickCenterTool);
  171. _eventFactory.AddEventListener(EventEnum.OnEditorDirty, OnEditorDirty);
  172.  
  173. RenderingServer.FramePostDraw += OnFramePostDraw;
  174. var navigationRegion = _editorTileMap.L_NavigationRegion.Instance;
  175. navigationRegion.Visible = false;
  176. navigationRegion.NavigationPolygon.AgentRadius = GameConfig.NavigationAgentRadius;
  177. navigationRegion.BakeFinished += OnBakeFinished;
  178. }
  179.  
  180. public void OnDestroy()
  181. {
  182. _eventFactory.RemoveAllEventListener();
  183. RenderingServer.FramePostDraw -= OnFramePostDraw;
  184. }
  185. public override void _Ready()
  186. {
  187. InitLayer();
  188. }
  189.  
  190. public override void _Process(double delta)
  191. {
  192. //触发绘制辅助线
  193. _editorTileMap.L_Brush.Instance.QueueRedraw();
  194. var newDelta = (float)delta;
  195. _drawFullRect = false;
  196. var position = GetLocalMousePosition();
  197. _mouseCellPosition = LocalToMap(position);
  198. _mousePosition = new Vector2(
  199. _mouseCellPosition.X * GameConfig.TileCellSize,
  200. _mouseCellPosition.Y * GameConfig.TileCellSize
  201. );
  202. if (!MapEditorToolsPanel.S_HBoxContainer.Instance.IsPositionOver(GetGlobalMousePosition())) //不在Ui节点上
  203. {
  204. //左键绘制
  205. if (_isLeftPressed)
  206. {
  207. if (MouseType == MouseButtonType.Pen) //绘制单格
  208. {
  209. if (_prevMouseCellPosition != _mouseCellPosition || !_changeFlag) //鼠标位置变过
  210. {
  211. _changeFlag = true;
  212. _prevMouseCellPosition = _mouseCellPosition;
  213. //绘制自动图块
  214. SetSingleAutoCell(_mouseCellPosition);
  215. }
  216. }
  217. else if (MouseType == MouseButtonType.Area) //绘制区域
  218. {
  219. _drawFullRect = true;
  220. }
  221. else if (MouseType == MouseButtonType.Drag) //拖拽
  222. {
  223. SetMapPosition(GetGlobalMousePosition() + _moveOffset);
  224. }
  225. }
  226. else if (_isRightPressed) //右键擦除
  227. {
  228. if (MouseType == MouseButtonType.Pen) //绘制单格
  229. {
  230. if (_prevMouseCellPosition != _mouseCellPosition || !_changeFlag) //鼠标位置变过
  231. {
  232. _changeFlag = true;
  233. _prevMouseCellPosition = _mouseCellPosition;
  234. EraseSingleAutoCell(_mouseCellPosition);
  235. }
  236. }
  237. else if (MouseType == MouseButtonType.Area) //绘制区域
  238. {
  239. _drawFullRect = true;
  240. }
  241. else if (MouseType == MouseButtonType.Drag) //拖拽
  242. {
  243. SetMapPosition(GetGlobalMousePosition() + _moveOffset);
  244. }
  245. }
  246. else if (_isMiddlePressed) //中键移动
  247. {
  248. SetMapPosition(GetGlobalMousePosition() + _moveOffset);
  249. }
  250. }
  251.  
  252. //绘制停止指定时间后, 生成导航网格
  253. if (_generateTimer > 0)
  254. {
  255. _generateTimer -= newDelta;
  256. if (_generateTimer <= 0)
  257. {
  258. //检测地形
  259. RunCheckHandler();
  260. }
  261. }
  262. }
  263.  
  264. /// <summary>
  265. /// 绘制辅助线
  266. /// </summary>
  267. public void DrawGuides()
  268. {
  269. if (_hasPreviewImage)
  270. {
  271. return;
  272. }
  273. CanvasItem canvasItem = _editorTileMap.L_Brush.Instance;
  274. //轴线
  275. canvasItem.DrawLine(new Vector2(0, 2000), new Vector2(0, -2000), Colors.Green);
  276. canvasItem.DrawLine(new Vector2(2000, 0), new Vector2( -2000, 0), Colors.Red);
  277. //绘制房间区域
  278. if (CurrRoomSize.X != 0 && CurrRoomSize.Y != 0)
  279. {
  280. canvasItem.DrawRect(
  281. new Rect2(
  282. (CurrRoomPosition + new Vector2I(1, 2)) * GameConfig.TileCellSize,
  283. (CurrRoomSize - new Vector2I(2, 3)) * GameConfig.TileCellSize
  284. ),
  285. Colors.Aqua, false, 5f / Scale.X
  286. );
  287. }
  288.  
  289. //绘制导航网格
  290. if (_checkTerrainFlag && _isGenerateTerrain && _polygonData != null)
  291. {
  292. foreach (var vector2s in _polygonData)
  293. {
  294. canvasItem.DrawPolygon(vector2s, new Color(0,1,1, 0.3f).MakeArray(vector2s.Length));
  295. }
  296. }
  297.  
  298. if (MouseType == MouseButtonType.Pen || MouseType == MouseButtonType.Area)
  299. {
  300. if (_drawFullRect) //绘制填充矩形
  301. {
  302. var size = TileSet.TileSize;
  303. var cellPos = _mouseStartCellPosition;
  304. var temp = size;
  305. if (_mouseStartCellPosition.X > _mouseCellPosition.X)
  306. {
  307. cellPos.X += 1;
  308. temp.X -= size.X;
  309. }
  310. if (_mouseStartCellPosition.Y > _mouseCellPosition.Y)
  311. {
  312. cellPos.Y += 1;
  313. temp.Y -= size.Y;
  314. }
  315.  
  316. var pos = cellPos * size;
  317. canvasItem.DrawRect(new Rect2(pos, _mousePosition - pos + temp), Colors.White, false, 2f / Scale.X);
  318. }
  319. else //绘制单格
  320. {
  321. canvasItem.DrawRect(new Rect2(_mousePosition, TileSet.TileSize), Colors.White, false, 2f / Scale.X);
  322. }
  323. }
  324. }
  325.  
  326. public override void _Input(InputEvent @event)
  327. {
  328. if (@event is InputEventMouseButton mouseButton)
  329. {
  330. if (mouseButton.ButtonIndex == MouseButton.Left) //左键
  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. SetRectAutoCell(_mouseStartCellPosition, _mouseCellPosition);
  343. _drawFullRect = false;
  344. }
  345. }
  346.  
  347. _isLeftPressed = mouseButton.Pressed;
  348. }
  349. else if (mouseButton.ButtonIndex == MouseButton.Right) //右键
  350. {
  351. if (mouseButton.Pressed) //按下
  352. {
  353. _moveOffset = Position - GetGlobalMousePosition();
  354. _mouseStartCellPosition = LocalToMap(GetLocalMousePosition());
  355. }
  356. else
  357. {
  358. _changeFlag = false;
  359. if (_drawFullRect) //松开, 提交擦除的矩形区域
  360. {
  361. EraseRectAutoCell(_mouseStartCellPosition, _mouseCellPosition);
  362. _drawFullRect = false;
  363. }
  364. }
  365. _isRightPressed = mouseButton.Pressed;
  366. }
  367. else if (mouseButton.ButtonIndex == MouseButton.WheelDown)
  368. {
  369. //缩小
  370. Shrink();
  371. }
  372. else if (mouseButton.ButtonIndex == MouseButton.WheelUp)
  373. {
  374. //放大
  375. Magnify();
  376. }
  377. else if (mouseButton.ButtonIndex == MouseButton.Middle)
  378. {
  379. _isMiddlePressed = mouseButton.Pressed;
  380. if (_isMiddlePressed)
  381. {
  382. _moveOffset = Position - GetGlobalMousePosition();
  383. }
  384. }
  385. }
  386. }
  387.  
  388. /// <summary>
  389. /// 尝试运行检查, 如果已经运行过了, 则没有效果
  390. /// </summary>
  391. public void TryRunCheckHandler()
  392. {
  393. if (_generateTimer > 0)
  394. {
  395. _generateTimer = -1;
  396. RunCheckHandler();
  397. }
  398. }
  399. //执行检测地形操作
  400. private void RunCheckHandler()
  401. {
  402. _isGenerateTerrain = false;
  403. //计算区域
  404. CalcTileRect(false);
  405. Debug.Log("开始检测是否可以生成地形...");
  406. if (CheckTerrain())
  407. {
  408. Debug.Log("开始绘制自动贴图...");
  409. GenerateTerrain();
  410. _isGenerateTerrain = true;
  411. }
  412. else
  413. {
  414. SetErrorCell(_checkTerrainErrorPosition);
  415. }
  416. }
  417.  
  418. //将指定层数据存入list中
  419. private void PushLayerDataToList(int layer, int sourceId, List<int> list)
  420. {
  421. var layerArray = GetUsedCellsById(layer, sourceId);
  422. foreach (var pos in layerArray)
  423. {
  424. var atlasCoords = GetCellAtlasCoords(layer, pos);
  425. list.Add(pos.X);
  426. list.Add(pos.Y);
  427. list.Add(_sourceId);
  428. list.Add(atlasCoords.X);
  429. list.Add(atlasCoords.Y);
  430. }
  431. }
  432.  
  433. private void SetLayerDataFromList(int layer, List<int> list)
  434. {
  435. for (var i = 0; i < list.Count; i += 5)
  436. {
  437. var pos = new Vector2I(list[i], list[i + 1]);
  438. var sourceId = list[i + 2];
  439. var atlasCoords = new Vector2I(list[i + 3], list[i + 4]);
  440. SetCell(layer, pos, sourceId, atlasCoords);
  441. if (layer == AutoFloorLayer)
  442. {
  443. _autoCellLayerGrid.Set(pos, true);
  444. }
  445. }
  446. }
  447.  
  448. /// <summary>
  449. /// 触发保存地图数据
  450. /// </summary>
  451. public void TriggerSave(RoomErrorType errorType, Action finish)
  452. {
  453. Debug.Log("保存地牢房间数据...");
  454. //执行创建预览图流程
  455. RunSavePreviewImage(() =>
  456. {
  457. //执行保存数据流程
  458. CurrRoomSplit.ErrorType = errorType;
  459. SaveRoomInfoConfig();
  460. SaveTileInfoConfig();
  461. SavePreinstallConfig();
  462. IsDirty = false;
  463. MapEditorPanel.SetTitleDirty(false);
  464. //派发保存事件
  465. EventManager.EmitEvent(EventEnum.OnEditorSave);
  466. if (finish != null)
  467. {
  468. finish();
  469. }
  470. });
  471. }
  472.  
  473. /// <summary>
  474. /// 加载地牢, 返回是否加载成功
  475. /// </summary>
  476. public bool Load(DungeonRoomSplit roomSplit)
  477. {
  478. //重新加载数据
  479. roomSplit.ReloadRoomInfo();
  480. roomSplit.ReloadTileInfo();
  481. roomSplit.ReloadPreinstall();
  482. CurrRoomSplit = roomSplit;
  483. var roomInfo = roomSplit.RoomInfo;
  484. var tileInfo = roomSplit.TileInfo;
  485.  
  486. CurrRoomPosition = roomInfo.Position.AsVector2I();
  487. SetMapSize(roomInfo.Size.AsVector2I(), true);
  488. CurrDoorConfigs.Clear();
  489. foreach (var doorAreaInfo in roomInfo.DoorAreaInfos)
  490. {
  491. CurrDoorConfigs.Add(doorAreaInfo.Clone());
  492. }
  493.  
  494. //初始化层级数据
  495. InitLayer();
  496. //地块数据
  497. SetLayerDataFromList(AutoFloorLayer, tileInfo.Floor);
  498. SetLayerDataFromList(AutoMiddleLayer, tileInfo.Middle);
  499. SetLayerDataFromList(AutoTopLayer, tileInfo.Top);
  500.  
  501. //如果有图块错误, 则找出错误的点位
  502. if (roomSplit.ErrorType == RoomErrorType.TileError)
  503. {
  504. RunCheckHandler();
  505. }
  506. else
  507. {
  508. //导航网格
  509. if (tileInfo.NavigationPolygon != null && tileInfo.NavigationVertices != null)
  510. {
  511. var polygon = _editorTileMap.L_NavigationRegion.Instance.NavigationPolygon;
  512. polygon.Vertices = tileInfo.NavigationVertices.Select(v => v.AsVector2()).ToArray();
  513. foreach (var p in tileInfo.NavigationPolygon)
  514. {
  515. polygon.AddPolygon(p);
  516. }
  517.  
  518. OnBakeFinished();
  519. }
  520. }
  521. //聚焦
  522. //MapEditorPanel.CallDelay(0.1f, OnClickCenterTool);
  523. //CallDeferred(nameof(OnClickCenterTool), null);
  524. //加载门编辑区域
  525. foreach (var doorAreaInfo in CurrDoorConfigs)
  526. {
  527. MapEditorToolsPanel.CreateDoorTool(doorAreaInfo);
  528. }
  529. //聚焦
  530. OnClickCenterTool(null);
  531. return true;
  532. }
  533.  
  534. private void InitLayer()
  535. {
  536. if (_initLayer)
  537. {
  538. return;
  539. }
  540.  
  541. _initLayer = true;
  542. //初始化层级数据
  543. AddLayer(CustomFloorLayer);
  544. SetLayerZIndex(CustomFloorLayer, CustomFloorLayer);
  545. AddLayer(AutoMiddleLayer);
  546. SetLayerZIndex(AutoMiddleLayer, AutoMiddleLayer);
  547. AddLayer(CustomMiddleLayer);
  548. SetLayerZIndex(CustomMiddleLayer, CustomMiddleLayer);
  549. AddLayer(AutoTopLayer);
  550. SetLayerZIndex(AutoTopLayer, AutoTopLayer);
  551. AddLayer(CustomTopLayer);
  552. SetLayerZIndex(CustomTopLayer, CustomTopLayer);
  553. }
  554.  
  555. //缩小
  556. private void Shrink()
  557. {
  558. var pos = GetLocalMousePosition();
  559. var scale = Scale / 1.1f;
  560. if (scale.LengthSquared() >= 0.5f)
  561. {
  562. Scale = scale;
  563. SetMapPosition(Position + pos * 0.1f * scale);
  564. }
  565. }
  566. //放大
  567. private void Magnify()
  568. {
  569. var pos = GetLocalMousePosition();
  570. var prevScale = Scale;
  571. var scale = prevScale * 1.1f;
  572. if (scale.LengthSquared() <= 2000)
  573. {
  574. Scale = scale;
  575. SetMapPosition(Position - pos * 0.1f * prevScale);
  576. }
  577. }
  578.  
  579. //绘制单个自动贴图
  580. private void SetSingleAutoCell(Vector2I position)
  581. {
  582. var tileCellData = _autoTileConfig.Floor;
  583. SetCell(GetFloorLayer(), position, tileCellData.SourceId, tileCellData.AutoTileCoords);
  584. //SetCell(GetFloorLayer(), position, _sourceId, _autoTileConfig.Floor.AutoTileCoords);
  585. if (!_autoCellLayerGrid.Contains(position.X, position.Y))
  586. {
  587. ResetGenerateTimer();
  588. _autoCellLayerGrid.Set(position.X, position.Y, true);
  589. }
  590. }
  591. //绘制区域自动贴图
  592. private void SetRectAutoCell(Vector2I start, Vector2I end)
  593. {
  594. ResetGenerateTimer();
  595. if (start.X > end.X)
  596. {
  597. var temp = end.X;
  598. end.X = start.X;
  599. start.X = temp;
  600. }
  601. if (start.Y > end.Y)
  602. {
  603. var temp = end.Y;
  604. end.Y = start.Y;
  605. start.Y = temp;
  606. }
  607.  
  608. var width = end.X - start.X + 1;
  609. var height = end.Y - start.Y + 1;
  610. for (var i = 0; i < width; i++)
  611. {
  612. for (var j = 0; j < height; j++)
  613. {
  614. var tileCellData = _autoTileConfig.Floor;
  615. SetCell(GetFloorLayer(), new Vector2I(start.X + i, start.Y + j), tileCellData.SourceId, tileCellData.AutoTileCoords);
  616. }
  617. }
  618.  
  619. _autoCellLayerGrid.SetRect(start, new Vector2I(width, height), true);
  620. }
  621.  
  622. //擦除单个自动图块
  623. private void EraseSingleAutoCell(Vector2I position)
  624. {
  625. EraseCell(GetFloorLayer(), position);
  626. if (_autoCellLayerGrid.Remove(position.X, position.Y))
  627. {
  628. ResetGenerateTimer();
  629. }
  630. }
  631. //擦除一个区域内的自动贴图
  632. private void EraseRectAutoCell(Vector2I start, Vector2I end)
  633. {
  634. ResetGenerateTimer();
  635. if (start.X > end.X)
  636. {
  637. var temp = end.X;
  638. end.X = start.X;
  639. start.X = temp;
  640. }
  641. if (start.Y > end.Y)
  642. {
  643. var temp = end.Y;
  644. end.Y = start.Y;
  645. start.Y = temp;
  646. }
  647.  
  648. var width = end.X - start.X + 1;
  649. var height = end.Y - start.Y + 1;
  650. for (var i = 0; i < width; i++)
  651. {
  652. for (var j = 0; j < height; j++)
  653. {
  654. EraseCell(GetFloorLayer(), new Vector2I(start.X + i, start.Y + j));
  655. }
  656. }
  657. _autoCellLayerGrid.RemoveRect(start, new Vector2I(width, height));
  658. }
  659.  
  660. //重置计时器
  661. private void ResetGenerateTimer()
  662. {
  663. _generateTimer = _generateInterval;
  664. _isGenerateTerrain = false;
  665. ClearLayer(AutoTopLayer);
  666. ClearLayer(AutoMiddleLayer);
  667. CloseErrorCell();
  668. //标记有修改数据
  669. EventManager.EmitEvent(EventEnum.OnEditorDirty);
  670. }
  671.  
  672. //重新计算房间区域
  673. private void CalcTileRect(bool refreshDoorTrans)
  674. {
  675. var rect = GetUsedRect();
  676. CurrRoomPosition = rect.Position;
  677. SetMapSize(rect.Size, refreshDoorTrans);
  678. }
  679. //检测是否有不合规的图块, 返回true表示图块正常
  680. private bool CheckTerrain()
  681. {
  682. _checkTerrainFlag = true;
  683. _autoCellLayerGrid.ForEach((x, y, flag) =>
  684. {
  685. if (flag)
  686. {
  687. if (!_autoCellLayerGrid.Contains(x, y + 1) && _autoCellLayerGrid.Contains(x, y + 2))
  688. {
  689. _checkTerrainFlag = false;
  690. _checkTerrainErrorPosition = new Vector2I(x, y + 1);
  691. return false;
  692. }
  693. }
  694.  
  695. return true;
  696. });
  697. return _checkTerrainFlag;
  698. }
  699. //生成自动图块 (地形)
  700. private void GenerateTerrain()
  701. {
  702. //ClearLayer(AutoFloorLayer);
  703. var list = new List<Vector2I>();
  704. var xStart = int.MaxValue;
  705. var yStart = int.MaxValue;
  706. var xEnd = int.MinValue;
  707. var yEnd = int.MinValue;
  708. _autoCellLayerGrid.ForEach((x, y, flag) =>
  709. {
  710. if (flag)
  711. {
  712. //计算范围
  713. if (x < xStart)
  714. xStart = x;
  715. else if (x > xEnd)
  716. xEnd = x;
  717.  
  718. if (y < yStart)
  719. yStart = y;
  720. else if (y > yEnd)
  721. yEnd = y;
  722. //填充墙壁
  723. if (!_autoCellLayerGrid.Contains(x, y - 1))
  724. {
  725. var left = _autoCellLayerGrid.Contains(x - 1, y - 1);
  726. var right = _autoCellLayerGrid.Contains(x + 1, y - 1);
  727. TileCellData tileCellData;
  728. if (left && right)
  729. {
  730. tileCellData = _autoTileConfig.Wall_Vertical_Single;
  731. }
  732. else if (left)
  733. {
  734. tileCellData = _autoTileConfig.Wall_Vertical_Left;
  735. }
  736. else if (right)
  737. {
  738. tileCellData = _autoTileConfig.Wall_Vertical_Right;
  739. }
  740. else
  741. {
  742. tileCellData = _autoTileConfig.Wall_Vertical_Center;
  743. }
  744. SetCell(GetFloorLayer(), new Vector2I(x, y - 1), tileCellData.SourceId, tileCellData.AutoTileCoords);
  745. }
  746. }
  747.  
  748. return true;
  749. });
  750. //绘制临时边界
  751. var temp1 = new List<Vector2I>();
  752. for (var x = xStart - 3; x <= xEnd + 3; x++)
  753. {
  754. var p1 = new Vector2I(x, yStart - 4);
  755. var p2 = new Vector2I(x, yEnd + 3);
  756. temp1.Add(p1);
  757. temp1.Add(p2);
  758. //上横
  759. SetCell(GetFloorLayer(), p1, _autoTileConfig.TopMask.SourceId, _autoTileConfig.TopMask.AutoTileCoords);
  760. //下横
  761. SetCell(GetFloorLayer(), p2, _autoTileConfig.TopMask.SourceId, _autoTileConfig.TopMask.AutoTileCoords);
  762. }
  763. for (var y = yStart - 4; y <= yEnd + 3; y++)
  764. {
  765. var p1 = new Vector2I(xStart - 3, y);
  766. var p2 = new Vector2I(xEnd + 3, y);
  767. temp1.Add(p1);
  768. temp1.Add(p2);
  769. //左竖
  770. SetCell(GetFloorLayer(), p1, _autoTileConfig.TopMask.SourceId, _autoTileConfig.TopMask.AutoTileCoords);
  771. //右竖
  772. SetCell(GetFloorLayer(), p2, _autoTileConfig.TopMask.SourceId, _autoTileConfig.TopMask.AutoTileCoords);
  773. }
  774. //计算需要绘制的图块
  775. var temp2 = new List<Vector2I>();
  776. for (var x = xStart - 2; x <= xEnd + 2; x++)
  777. {
  778. for (var y = yStart - 3; y <= yEnd + 2; y++)
  779. {
  780. if (!_autoCellLayerGrid.Contains(x, y) && !_autoCellLayerGrid.Contains(x, y + 1))
  781. {
  782. list.Add(new Vector2I(x, y));
  783. if (!IsMaskCollisionGround(_autoCellLayerGrid, x, y))
  784. {
  785. temp2.Add(new Vector2I(x, y));
  786. }
  787. }
  788. }
  789. }
  790. var arr = new Array<Vector2I>(list);
  791. //绘制自动图块
  792. SetCellsTerrainConnect(AutoFloorLayer, arr, _terrainSet, _terrain, false);
  793. //擦除临时边界
  794. for (var i = 0; i < temp1.Count; i++)
  795. {
  796. EraseCell(GetFloorLayer(), temp1[i]);
  797. }
  798.  
  799. //计算区域
  800. CalcTileRect(true);
  801. //开始绘制导航网格
  802. GenerateNavigation();
  803.  
  804. //擦除临时边界2
  805. for (var i = 0; i < temp2.Count; i++)
  806. {
  807. EraseCell(GetFloorLayer(), temp2[i]);
  808. }
  809. //将墙壁移动到指定层
  810. MoveTerrainCell();
  811. }
  812.  
  813. private bool IsMaskCollisionGround(InfiniteGrid<bool> autoCellLayerGrid, int x, int y)
  814. {
  815. for (var i = -2; i <= 2; i++)
  816. {
  817. for (var j = -2; j <= 3; j++)
  818. {
  819. if (autoCellLayerGrid.Contains(x + i, y + j))
  820. {
  821. return true;
  822. }
  823. }
  824. }
  825.  
  826. return false;
  827. }
  828. //将自动生成的图块从 AutoFloorLayer 移动到指定图层中
  829. private void MoveTerrainCell()
  830. {
  831. ClearLayer(AutoTopLayer);
  832. ClearLayer(AutoMiddleLayer);
  833. var x = CurrRoomPosition.X;
  834. var y = CurrRoomPosition.Y;
  835. var w = CurrRoomSize.X;
  836. var h = CurrRoomSize.Y;
  837.  
  838. for (var i = 0; i < w; i++)
  839. {
  840. for (var j = 0; j < h; j++)
  841. {
  842. var pos = new Vector2I(x + i, y + j);
  843. if (!_autoCellLayerGrid.Contains(pos) && GetCellSourceId(AutoFloorLayer, pos) != -1)
  844. {
  845. var atlasCoords = GetCellAtlasCoords(AutoFloorLayer, pos);
  846. var layer = _autoTileConfig.GetLayer(atlasCoords);
  847. if (layer == GameConfig.MiddleMapLayer)
  848. {
  849. layer = AutoMiddleLayer;
  850. }
  851. else if (layer == GameConfig.TopMapLayer)
  852. {
  853. layer = AutoTopLayer;
  854. }
  855. else
  856. {
  857. Debug.LogError($"异常图块: {pos}, 这个图块的图集坐标'{atlasCoords}'不属于'MiddleMapLayer'和'TopMapLayer'!");
  858. continue;
  859. }
  860. EraseCell(AutoFloorLayer, pos);
  861. SetCell(layer, pos, _sourceId, atlasCoords);
  862. }
  863. }
  864. }
  865. }
  866.  
  867. //生成导航网格
  868. private void GenerateNavigation()
  869. {
  870. var navigationRegion = _editorTileMap.L_NavigationRegion.Instance;
  871. var navigationPolygon = navigationRegion.NavigationPolygon;
  872. navigationPolygon.Clear();
  873. navigationPolygon.ClearPolygons();
  874. navigationPolygon.ClearOutlines();
  875. var endPos = CurrRoomPosition + CurrRoomSize;
  876. navigationPolygon.AddOutline(new []
  877. {
  878. CurrRoomPosition * GameConfig.TileCellSize,
  879. new Vector2(endPos.X, CurrRoomPosition.Y) * GameConfig.TileCellSize,
  880. endPos * GameConfig.TileCellSize,
  881. new Vector2(CurrRoomPosition.X, endPos.Y) * GameConfig.TileCellSize
  882. });
  883. navigationRegion.BakeNavigationPolygon(false);
  884. }
  885.  
  886. //设置显示的错误cell, 会标记上红色的闪烁动画
  887. private void SetErrorCell(Vector2I pos)
  888. {
  889. MapEditorPanel.S_ErrorCell.Instance.Position = pos * GameConfig.TileCellSize;
  890. MapEditorPanel.S_ErrorCellAnimationPlayer.Instance.Play(AnimatorNames.Show);
  891. }
  892.  
  893. //关闭显示的错误cell
  894. private void CloseErrorCell()
  895. {
  896. MapEditorPanel.S_ErrorCellAnimationPlayer.Instance.Stop();
  897. }
  898.  
  899. private int GetFloorLayer()
  900. {
  901. return AutoFloorLayer;
  902. }
  903.  
  904. private int GetMiddleLayer()
  905. {
  906. return AutoMiddleLayer;
  907. }
  908.  
  909. private int GetTopLayer()
  910. {
  911. return AutoTopLayer;
  912. }
  913.  
  914. /// <summary>
  915. /// 选中拖拽功能
  916. /// </summary>
  917. private void OnSelectHandTool(object arg)
  918. {
  919. MouseType = MouseButtonType.Drag;
  920. }
  921. /// <summary>
  922. /// 选中画笔攻击
  923. /// </summary>
  924. private void OnSelectPenTool(object arg)
  925. {
  926. MouseType = MouseButtonType.Pen;
  927. }
  928.  
  929. /// <summary>
  930. /// 选中绘制区域功能
  931. /// </summary>
  932. private void OnSelectRectTool(object arg)
  933. {
  934. MouseType = MouseButtonType.Area;
  935. }
  936.  
  937. /// <summary>
  938. /// 选择编辑门区域
  939. /// </summary>
  940. private void OnSelectEditTool(object arg)
  941. {
  942. MouseType = MouseButtonType.Edit;
  943. }
  944.  
  945. /// <summary>
  946. /// 聚焦
  947. /// </summary>
  948. private void OnClickCenterTool(object arg)
  949. {
  950. var pos = MapEditorPanel.S_SubViewport.Instance.Size / 2;
  951. if (CurrRoomSize.X == 0 && CurrRoomSize.Y == 0) //聚焦原点
  952. {
  953. SetMapPosition(pos);
  954. }
  955. else //聚焦地图中心点
  956. {
  957. SetMapPosition(pos - (CurrRoomPosition + CurrRoomSize / 2) * TileSet.TileSize * Scale);
  958. }
  959. }
  960. //房间数据有修改
  961. private void OnEditorDirty(object obj)
  962. {
  963. IsDirty = true;
  964. MapEditorPanel.SetTitleDirty(true);
  965. }
  966.  
  967. /// <summary>
  968. /// 创建地牢房间门区域
  969. /// </summary>
  970. /// <param name="direction">门方向</param>
  971. /// <param name="start">起始坐标, 单位: 像素</param>
  972. /// <param name="end">结束坐标, 单位: 像素</param>
  973. public DoorAreaInfo CreateDoorArea(DoorDirection direction, int start, int end)
  974. {
  975. var doorAreaInfo = new DoorAreaInfo();
  976. doorAreaInfo.Direction = direction;
  977. doorAreaInfo.Start = start;
  978. doorAreaInfo.End = end;
  979. //doorAreaInfo.CalcPosition(_roomPosition, _roomSize);
  980. CurrDoorConfigs.Add(doorAreaInfo);
  981. return doorAreaInfo;
  982. }
  983.  
  984. /// <summary>
  985. /// 检测门区域数据是否可以提交
  986. /// </summary>
  987. /// <param name="direction">门方向</param>
  988. /// <param name="start">起始坐标, 单位: 像素</param>
  989. /// <param name="end">结束坐标, 单位: 像素</param>
  990. /// <returns></returns>
  991. public bool CheckDoorArea(DoorDirection direction, int start, int end)
  992. {
  993. foreach (var item in CurrDoorConfigs)
  994. {
  995. if (item.Direction == direction)
  996. {
  997. if (CheckValueCollision(item.Start, item.End, start, end))
  998. {
  999. return false;
  1000. }
  1001. }
  1002. }
  1003.  
  1004. return true;
  1005. }
  1006. /// <summary>
  1007. /// 检测门区域数据是否可以提交
  1008. /// </summary>
  1009. /// <param name="target">需要检测的门</param>
  1010. /// <param name="start">起始坐标, 单位: 像素</param>
  1011. /// <param name="end">结束坐标, 单位: 像素</param>
  1012. public bool CheckDoorArea(DoorAreaInfo target, int start, int end)
  1013. {
  1014. foreach (var item in CurrDoorConfigs)
  1015. {
  1016. if (item.Direction == target.Direction && item != target)
  1017. {
  1018. if (CheckValueCollision(item.Start, item.End, start, end))
  1019. {
  1020. return false;
  1021. }
  1022. }
  1023. }
  1024.  
  1025. return true;
  1026. }
  1027. private bool CheckValueCollision(float o1, float o2, float h1, float h2)
  1028. {
  1029. var size = GameConfig.TileCellSize;
  1030. return !(h2 < o1 - 3 * size || o2 + 3 * size < h1);
  1031. }
  1032.  
  1033. /// <summary>
  1034. /// 移除门区域数据
  1035. /// </summary>
  1036. public void RemoveDoorArea(DoorAreaInfo doorAreaInfo)
  1037. {
  1038. CurrDoorConfigs.Remove(doorAreaInfo);
  1039. }
  1040. //保存房间配置
  1041. private void SaveRoomInfoConfig()
  1042. {
  1043. //存入本地
  1044. var roomInfo = CurrRoomSplit.RoomInfo;
  1045. if (!HasTerrainError) //没有绘制错误
  1046. {
  1047. roomInfo.Size = new SerializeVector2(CurrRoomSize);
  1048. roomInfo.Position = new SerializeVector2(CurrRoomPosition);
  1049. }
  1050. else
  1051. {
  1052. roomInfo.Position = new SerializeVector2(CurrRoomPosition - Vector2I.One);
  1053. roomInfo.Size = new SerializeVector2(CurrRoomSize + new Vector2I(2, 2));
  1054. }
  1055.  
  1056. roomInfo.DoorAreaInfos.Clear();
  1057. roomInfo.DoorAreaInfos.AddRange(CurrDoorConfigs);
  1058. roomInfo.ClearCompletionDoorArea();
  1059. MapProjectManager.SaveRoomInfo(CurrRoomSplit);
  1060. }
  1061.  
  1062. //保存地块数据
  1063. public void SaveTileInfoConfig()
  1064. {
  1065. //存入本地
  1066. var tileInfo = CurrRoomSplit.TileInfo;
  1067. if (tileInfo.NavigationPolygon == null)
  1068. {
  1069. tileInfo.NavigationPolygon = new List<int[]>();
  1070. }
  1071. else
  1072. {
  1073. tileInfo.NavigationPolygon.Clear();
  1074. }
  1075. if (tileInfo.NavigationVertices == null)
  1076. {
  1077. tileInfo.NavigationVertices = new List<SerializeVector2>();
  1078. }
  1079. else
  1080. {
  1081. tileInfo.NavigationVertices.Clear();
  1082. }
  1083. var polygon = _editorTileMap.L_NavigationRegion.Instance.NavigationPolygon;
  1084. tileInfo.NavigationPolygon.AddRange(polygon.Polygons);
  1085. tileInfo.NavigationVertices.AddRange(polygon.Vertices.Select(v => new SerializeVector2(v)));
  1086. tileInfo.Floor.Clear();
  1087. tileInfo.Middle.Clear();
  1088. tileInfo.Top.Clear();
  1089.  
  1090. PushLayerDataToList(AutoFloorLayer, _sourceId, tileInfo.Floor);
  1091. PushLayerDataToList(AutoMiddleLayer, _sourceId, tileInfo.Middle);
  1092. PushLayerDataToList(AutoTopLayer, _sourceId, tileInfo.Top);
  1093. MapProjectManager.SaveRoomTileInfo(CurrRoomSplit);
  1094. }
  1095.  
  1096. /// <summary>
  1097. /// 保存预设数据
  1098. /// </summary>
  1099. public void SavePreinstallConfig()
  1100. {
  1101. //存入本地
  1102. MapProjectManager.SaveRoomPreinstall(CurrRoomSplit);
  1103. }
  1104.  
  1105. /// <summary>
  1106. /// 获取相机中心点坐标
  1107. /// </summary>
  1108. public Vector2I GetCenterPosition()
  1109. {
  1110. var pos = ToLocal(MapEditorPanel.S_SubViewport.Instance.Size / 2);
  1111. return new Vector2I((int)pos.X, (int)pos.Y);
  1112. }
  1113. /// <summary>
  1114. /// 设置相机看向的点
  1115. /// </summary>
  1116. public void SetLookPosition(Vector2 pos)
  1117. {
  1118. SetMapPosition(-pos * Scale + MapEditorPanel.S_SubViewport.Instance.Size / 2);
  1119. //SetMapPosition(pos * Scale);
  1120. //SetMapPosition(pos + MapEditorPanel.S_SubViewport.Instance.Size / 2);
  1121. }
  1122. /// <summary>
  1123. /// 设置地图坐标
  1124. /// </summary>
  1125. public void SetMapPosition(Vector2 pos)
  1126. {
  1127. Position = pos;
  1128. MapEditorToolsPanel.SetToolTransform(pos, Scale);
  1129. }
  1130.  
  1131. //设置地图大小
  1132. private void SetMapSize(Vector2I size, bool refreshDoorTrans)
  1133. {
  1134. if (CurrRoomSize != size)
  1135. {
  1136. CurrRoomSize = size;
  1137.  
  1138. if (refreshDoorTrans)
  1139. {
  1140. MapEditorToolsPanel.SetDoorHoverToolTransform(CurrRoomPosition, CurrRoomSize);
  1141. }
  1142. }
  1143. }
  1144.  
  1145. private bool _hasPreviewImage = false;
  1146. private Action _previewFinish;
  1147. private int _previewIndex = 0;
  1148. private Vector2I _tempViewportSize;
  1149. private Vector2 _tempMapPos;
  1150. private Vector2 _tempMapScale;
  1151. private bool _tempAutoFloorLayer;
  1152. private bool _tempCustomFloorLayer;
  1153. private bool _tempAutoMiddleLayer;
  1154. private bool _tempCustomMiddleLayer;
  1155. private bool _tempAutoTopLayer;
  1156. private bool _tempCustomTopLayer;
  1157.  
  1158. private void RunSavePreviewImage(Action action)
  1159. {
  1160. if (_hasPreviewImage)
  1161. {
  1162. return;
  1163. }
  1164.  
  1165. _previewIndex = 0;
  1166. _previewFinish = action;
  1167. _hasPreviewImage = true;
  1168. //先截图, 将图像数据放置到 S_MapView2 节点上
  1169. var subViewport = MapEditorPanel.S_SubViewport.Instance;
  1170. var viewportTexture = subViewport.GetTexture();
  1171. var tex = ImageTexture.CreateFromImage(viewportTexture.GetImage());
  1172. var textureRect = MapEditorPanel.S_MapView2.Instance;
  1173. textureRect.Texture = tex;
  1174. textureRect.Visible = true;
  1175. //调整绘制视图大小
  1176. _tempViewportSize = subViewport.Size;
  1177. subViewport.Size = new Vector2I(GameConfig.PreviewImageSize, GameConfig.PreviewImageSize);
  1178. //调整tileMap
  1179. _tempMapPos = Position;
  1180. _tempMapScale = Scale;
  1181. //中心点
  1182. var pos = new Vector2(GameConfig.PreviewImageSize / 2f, GameConfig.PreviewImageSize / 2f);
  1183. if (CurrRoomSize.X == 0 && CurrRoomSize.Y == 0) //聚焦原点
  1184. {
  1185. Position = pos;
  1186. }
  1187. else //聚焦地图中心点
  1188. {
  1189. var tempPos = new Vector2(CurrRoomSize.X, CurrRoomSize.Y);
  1190. //var tempPos = new Vector2(CurrRoomSize.X + 2, CurrRoomSize.Y + 2);
  1191. var mapSize = tempPos * TileSet.TileSize;
  1192. var axis = Mathf.Max(mapSize.X, mapSize.Y);
  1193. var targetScale = GameConfig.PreviewImageSize / axis;
  1194. Scale = new Vector2(targetScale, targetScale);
  1195. Position = pos - (CurrRoomPosition + tempPos / 2f) * TileSet.TileSize * targetScale;
  1196. }
  1197. //隐藏工具栏
  1198. MapEditorToolsPanel.Visible = false;
  1199. //显示所有层级
  1200. _tempAutoFloorLayer = IsLayerEnabled(AutoFloorLayer);
  1201. _tempCustomFloorLayer = IsLayerEnabled(CustomFloorLayer);
  1202. _tempAutoMiddleLayer = IsLayerEnabled(AutoMiddleLayer);
  1203. _tempCustomMiddleLayer = IsLayerEnabled(CustomMiddleLayer);
  1204. _tempAutoTopLayer = IsLayerEnabled(AutoTopLayer);
  1205. _tempCustomTopLayer = IsLayerEnabled(CustomTopLayer);
  1206.  
  1207. SetLayerEnabled(AutoFloorLayer, true);
  1208. SetLayerEnabled(CustomFloorLayer, true);
  1209. SetLayerEnabled(AutoMiddleLayer, true);
  1210. SetLayerEnabled(CustomMiddleLayer, true);
  1211. SetLayerEnabled(AutoTopLayer, true);
  1212. SetLayerEnabled(CustomTopLayer, true);
  1213. }
  1214.  
  1215. private void OnFramePostDraw()
  1216. {
  1217. if (_hasPreviewImage)
  1218. {
  1219. _previewIndex++;
  1220. if (_previewIndex == 2)
  1221. {
  1222. var textureRect = MapEditorPanel.S_MapView2.Instance;
  1223. var texture = textureRect.Texture;
  1224. textureRect.Texture = null;
  1225. texture.Dispose();
  1226. textureRect.Visible = false;
  1227. //还原工具栏
  1228. MapEditorToolsPanel.Visible = true;
  1229. //还原层级显示
  1230. SetLayerEnabled(AutoFloorLayer, _tempAutoFloorLayer);
  1231. SetLayerEnabled(CustomFloorLayer, _tempCustomFloorLayer);
  1232. SetLayerEnabled(AutoMiddleLayer, _tempAutoMiddleLayer);
  1233. SetLayerEnabled(CustomMiddleLayer, _tempCustomMiddleLayer);
  1234. SetLayerEnabled(AutoTopLayer, _tempAutoTopLayer);
  1235. SetLayerEnabled(CustomTopLayer, _tempCustomTopLayer);
  1236.  
  1237. //保存预览图
  1238. var subViewport = MapEditorPanel.S_SubViewport.Instance;
  1239. var viewportTexture = subViewport.GetTexture();
  1240. var image = viewportTexture.GetImage();
  1241. image.Resize(GameConfig.PreviewImageSize, GameConfig.PreviewImageSize, Image.Interpolation.Nearest);
  1242. CurrRoomSplit.PreviewImage = ImageTexture.CreateFromImage(image);
  1243. MapProjectManager.SaveRoomPreviewImage(CurrRoomSplit, image);
  1244. //还原tileMap
  1245. Position = _tempMapPos;
  1246. Scale = _tempMapScale;
  1247. //还原绘制视图
  1248. subViewport.Size = _tempViewportSize;
  1249. _previewFinish();
  1250. _hasPreviewImage = false;
  1251. }
  1252. }
  1253. }
  1254. private void OnBakeFinished()
  1255. {
  1256. var polygonData = _editorTileMap.L_NavigationRegion.Instance.NavigationPolygon;
  1257. var polygons = polygonData.Polygons;
  1258. var vertices = polygonData.Vertices;
  1259. _polygonData = new Vector2[polygons.Count][];
  1260. for (var i = 0; i < polygons.Count; i++)
  1261. {
  1262. var polygon = polygons[i];
  1263. var v2Array = new Vector2[polygon.Length];
  1264. for (var j = 0; j < polygon.Length; j++)
  1265. {
  1266. v2Array[j] = vertices[polygon[j]];
  1267. }
  1268. _polygonData[i] = v2Array;
  1269. }
  1270. }
  1271. }