Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / DungeonRoomTemplate.cs
  1.  
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text.Json;
  7. using Godot;
  8.  
  9. [Tool]
  10. public partial class DungeonRoomTemplate : TileMap
  11. {
  12. /// <summary>
  13. /// 是否启用编辑模式
  14. /// </summary>
  15. [Export]
  16. public bool EnableEdit = false;
  17.  
  18. #if TOOLS
  19. //是否悬停在线上
  20. private bool _hover = false;
  21.  
  22. //悬停点
  23. private Vector2 _hoverPoint1;
  24. private Vector2 _hoverPoint2;
  25. private DoorDirection _hoverDirection;
  26. private bool _canPut = false;
  27.  
  28. //选中点
  29. private bool _hasActivePoint = false;
  30. //选中左/右点
  31. private byte _activePointType = 0;
  32. private DoorAreaInfo _activeArea = null;
  33.  
  34. //拖拽
  35. private bool _isDrag = false;
  36. private float _startDragValue;
  37. private Vector2 _startDragPositionValue;
  38. private bool _dragHasCollision = false;
  39.  
  40. private bool _mouseDown = false;
  41.  
  42. //房间配置
  43. private DungeonRoomInfo _dungeonRoomInfo;
  44. private Rect2 _prevRect;
  45.  
  46. //是否能是否按下
  47. private bool _clickSave = false;
  48.  
  49. private DungeonTile _dungeonTile;
  50. private TileDrawHandler _tileDrawHandler;
  51.  
  52. //计算导航的计时器
  53. private float _calcTileNavTimer = 0;
  54.  
  55. private partial class TileDrawHandler : Node2D
  56. {
  57. public DungeonRoomTemplate RoomTemplate;
  58.  
  59. public override void _Draw()
  60. {
  61. if (!Engine.IsEditorHint() || RoomTemplate == null)
  62. {
  63. return;
  64. }
  65. if (RoomTemplate.TileSet != null)
  66. {
  67. //绘制地图轮廓
  68. var mapRange = CalcTileRange(RoomTemplate);
  69. mapRange.Position -= new Vector2(2, 2);
  70. mapRange.Size += new Vector2(4, 4);
  71. DrawRect(mapRange, RoomTemplate._hover ? Colors.Green : new Color(0.03137255F, 0.59607846F, 0.03137255F), false, 2);
  72.  
  73. //绘制悬停
  74. if (RoomTemplate._hover && !RoomTemplate._isDrag)
  75. {
  76. if (!RoomTemplate._hasActivePoint) //这里判断是否悬停在拖动点上
  77. {
  78. var color = RoomTemplate._canPut ? new Color(0, 1, 0, 0.2f) : new Color(1, 0, 0, 0.2f);
  79. switch (RoomTemplate._hoverDirection)
  80. {
  81. case DoorDirection.E:
  82. DrawRect(
  83. new Rect2(new Vector2(RoomTemplate._hoverPoint1.X + 2, RoomTemplate._hoverPoint1.Y), 30,
  84. RoomTemplate._hoverPoint2.Y - RoomTemplate._hoverPoint1.Y), color);
  85. DrawCircle(new Vector2(RoomTemplate._hoverPoint1.X + 2, RoomTemplate._hoverPoint1.Y), 5, color);
  86. DrawCircle(new Vector2(RoomTemplate._hoverPoint2.X + 2, RoomTemplate._hoverPoint2.Y), 5, color);
  87. break;
  88. case DoorDirection.W:
  89. DrawRect(
  90. new Rect2(new Vector2(RoomTemplate._hoverPoint1.X - 2 - 30, RoomTemplate._hoverPoint1.Y), 30,
  91. RoomTemplate._hoverPoint2.Y - RoomTemplate._hoverPoint1.Y), color);
  92. DrawCircle(new Vector2(RoomTemplate._hoverPoint1.X - 2, RoomTemplate._hoverPoint1.Y), 5, color);
  93. DrawCircle(new Vector2(RoomTemplate._hoverPoint2.X - 2, RoomTemplate._hoverPoint2.Y), 5, color);
  94. break;
  95. case DoorDirection.S:
  96. DrawRect(
  97. new Rect2(new Vector2(RoomTemplate._hoverPoint1.X, RoomTemplate._hoverPoint1.Y + 2),
  98. RoomTemplate._hoverPoint2.X - RoomTemplate._hoverPoint1.X, 30), color);
  99. DrawCircle(new Vector2(RoomTemplate._hoverPoint1.X, RoomTemplate._hoverPoint1.Y + 2), 5, color);
  100. DrawCircle(new Vector2(RoomTemplate._hoverPoint2.X, RoomTemplate._hoverPoint2.Y + 2), 5, color);
  101. break;
  102. case DoorDirection.N:
  103. DrawRect(
  104. new Rect2(new Vector2(RoomTemplate._hoverPoint1.X, RoomTemplate._hoverPoint1.Y - 30 - 2),
  105. RoomTemplate._hoverPoint2.X - RoomTemplate._hoverPoint1.X, 30), color);
  106. DrawCircle(new Vector2(RoomTemplate._hoverPoint1.X, RoomTemplate._hoverPoint1.Y - 2), 5, color);
  107. DrawCircle(new Vector2(RoomTemplate._hoverPoint2.X, RoomTemplate._hoverPoint2.Y - 2), 5, color);
  108. break;
  109. }
  110. }
  111. }
  112.  
  113. //绘制区域
  114. if (RoomTemplate._dungeonRoomInfo != null && RoomTemplate._dungeonRoomInfo.DoorAreaInfos != null)
  115. {
  116. var color2 = new Color(0, 1, 0, 0.8f);
  117. //绘制已经存在的
  118. foreach (var doorAreaInfo in RoomTemplate._dungeonRoomInfo.DoorAreaInfos)
  119. {
  120. var flag = RoomTemplate._hasActivePoint && RoomTemplate._activeArea == doorAreaInfo;
  121. var color3 = (flag && RoomTemplate._activePointType == 0)
  122. ? (RoomTemplate._isDrag
  123. ? (RoomTemplate._dragHasCollision
  124. ? new Color(1, 0, 0, 0.8f)
  125. : new Color(0.2F, 0.4117647F, 0.8392157F, 0.8f))
  126. : new Color(1, 1, 1, 0.8f))
  127. : color2;
  128. var color4 = (flag && RoomTemplate._activePointType == 1)
  129. ? (RoomTemplate._isDrag
  130. ? (RoomTemplate._dragHasCollision
  131. ? new Color(1, 0, 0, 0.8f)
  132. : new Color(0.2F, 0.4117647F, 0.8392157F, 0.8f))
  133. : new Color(1, 1, 1, 0.8f))
  134. : color2;
  135. switch (doorAreaInfo.Direction)
  136. {
  137. case DoorDirection.E:
  138. DrawRect(
  139. new Rect2(
  140. new Vector2(mapRange.Position.X + mapRange.Size.X,
  141. mapRange.Position.Y + doorAreaInfo.Start + 2), 30,
  142. doorAreaInfo.End - doorAreaInfo.Start), color2);
  143. DrawCircle(
  144. new Vector2(mapRange.Position.X + mapRange.Size.X,
  145. mapRange.Position.Y + doorAreaInfo.Start + 2), 5, color3);
  146. DrawCircle(
  147. new Vector2(mapRange.Position.X + mapRange.Size.X,
  148. mapRange.Position.Y + doorAreaInfo.End + 2),
  149. 5, color4);
  150. break;
  151. case DoorDirection.W:
  152. DrawRect(
  153. new Rect2(
  154. new Vector2(mapRange.Position.X - 30, mapRange.Position.Y + doorAreaInfo.Start + 2),
  155. 30, doorAreaInfo.End - doorAreaInfo.Start), color2);
  156. DrawCircle(new Vector2(mapRange.Position.X, mapRange.Position.Y + doorAreaInfo.Start + 2),
  157. 5,
  158. color3);
  159. DrawCircle(new Vector2(mapRange.Position.X, mapRange.Position.Y + doorAreaInfo.End + 2), 5,
  160. color4);
  161. break;
  162. case DoorDirection.S:
  163. DrawRect(
  164. new Rect2(
  165. new Vector2(mapRange.Position.X + doorAreaInfo.Start + 2,
  166. mapRange.Position.Y + mapRange.Size.Y), doorAreaInfo.End - doorAreaInfo.Start,
  167. 30),
  168. color2);
  169. DrawCircle(
  170. new Vector2(mapRange.Position.X + doorAreaInfo.Start + 2,
  171. mapRange.Position.Y + mapRange.Size.Y), 5, color3);
  172. DrawCircle(
  173. new Vector2(mapRange.Position.X + doorAreaInfo.End + 2,
  174. mapRange.Position.Y + mapRange.Size.Y),
  175. 5, color4);
  176. break;
  177. case DoorDirection.N:
  178. DrawRect(
  179. new Rect2(
  180. new Vector2(mapRange.Position.X + doorAreaInfo.Start + 2, mapRange.Position.Y - 30),
  181. doorAreaInfo.End - doorAreaInfo.Start, 30), color2);
  182. DrawCircle(new Vector2(mapRange.Position.X + doorAreaInfo.Start + 2, mapRange.Position.Y),
  183. 5,
  184. color3);
  185. DrawCircle(new Vector2(mapRange.Position.X + doorAreaInfo.End + 2, mapRange.Position.Y), 5,
  186. color4);
  187. break;
  188. }
  189. }
  190. }
  191. //绘制导航, 现在有点问题, 绘制的内容会被自身的 tile 所挡住
  192. if (RoomTemplate._dungeonTile != null)
  193. {
  194. var result = RoomTemplate._dungeonTile.GetGenerateNavigationResult();
  195. if (result != null)
  196. {
  197. if (result.Success)
  198. {
  199. var polygonData = RoomTemplate._dungeonTile.GetPolygonData();
  200. Utils.DrawNavigationPolygon(this, polygonData, 2);
  201. }
  202. else
  203. {
  204. var color = new Color(1, 0, 0, 0.5f);
  205. var tileCellSize = GameConfig.TileCellSize;
  206. var point = (result.Exception.Point + new Vector2(0.5f, 0.5f)) * tileCellSize;
  207. DrawCircle(point, 4, color);
  208. DrawLine(point + new Vector2(-tileCellSize / 2f, -tileCellSize / 2f), point + new Vector2(tileCellSize / 2f, tileCellSize / 2f), color, 2);
  209. DrawLine(point + new Vector2(-tileCellSize / 2f, tileCellSize / 2f), point + new Vector2(tileCellSize / 2f, -tileCellSize / 2f), color, 2);
  210. }
  211. }
  212. }
  213. }
  214. }
  215.  
  216. }
  217. public override void _Ready()
  218. {
  219. if (!Engine.IsEditorHint())
  220. {
  221. return;
  222. }
  223. EnableEdit = false;
  224. }
  225.  
  226. public override void _Process(double delta)
  227. {
  228. if (!Engine.IsEditorHint())
  229. {
  230. return;
  231. }
  232.  
  233. if (TileSet == null)
  234. {
  235. return;
  236. }
  237.  
  238. if (_dungeonTile == null)
  239. {
  240. _dungeonTile = new DungeonTile(this);
  241. _dungeonTile.SetFloorAtlasCoords(new List<Vector2I>() { new Vector2I(0, 8) });
  242. OnTileChanged();
  243. var callable = new Callable(this, nameof(OnTileChanged));
  244. if (!IsConnected("changed", callable))
  245. {
  246. Connect("changed", callable);
  247. }
  248. }
  249.  
  250. if (_tileDrawHandler == null)
  251. {
  252. _tileDrawHandler = GetNodeOrNull<TileDrawHandler>("TileDrawHandler");
  253. if (_tileDrawHandler == null)
  254. {
  255. _tileDrawHandler = new TileDrawHandler();
  256. _tileDrawHandler.RoomTemplate = this;
  257. _tileDrawHandler.Name = "TileDrawHandler";
  258. _tileDrawHandler.ZIndex = 100;
  259. AddChild(_tileDrawHandler);
  260. }
  261. else
  262. {
  263. _tileDrawHandler.RoomTemplate = this;
  264. }
  265. }
  266. //导航计算
  267. if (_calcTileNavTimer > 0)
  268. {
  269. _calcTileNavTimer -= (float)delta;
  270. //重新计算导航
  271. if (_calcTileNavTimer <= 0)
  272. {
  273. _dungeonTile.GenerateNavigationPolygon(0);
  274. }
  275. }
  276.  
  277. //加载配置
  278. var initConfigs = false;
  279. if (_dungeonRoomInfo == null)
  280. {
  281. initConfigs = true;
  282.  
  283. var path = SceneFilePath;
  284. if (!string.IsNullOrEmpty(path))
  285. {
  286. var start = GameConfig.RoomTileDir.Length + 6;
  287. var name = path.Substring(start, path.Length - start - 5);
  288. ReadConfig(CalcTileRange(this), name);
  289. }
  290. }
  291.  
  292. //按键检测
  293. var isClick = false;
  294. if (Input.IsMouseButtonPressed(MouseButton.Left))
  295. {
  296. if (!_mouseDown)
  297. {
  298. _mouseDown = true;
  299. isClick = true;
  300. }
  301. }
  302. else if (_mouseDown)
  303. {
  304. _mouseDown = false;
  305. isClick = false;
  306. }
  307.  
  308. if (Input.IsMouseButtonPressed(MouseButton.Middle)) //中键移除门
  309. {
  310. if (EnableEdit && _activeArea != null)
  311. {
  312. RemoveDoorArea(_activeArea);
  313. _hasActivePoint = false;
  314. _activeArea = null;
  315. }
  316. }
  317. else if (TileSet != null) //编辑操作
  318. {
  319. var mapRect = CalcTileRange(this);
  320. var mousePosition = GetLocalMousePosition();
  321.  
  322. if (mapRect != _prevRect)
  323. {
  324. if (!initConfigs)
  325. {
  326. OnMapRectChange();
  327. }
  328. }
  329.  
  330. _prevRect = mapRect;
  331. if (EnableEdit)
  332. {
  333. var tileSize = TileSet.TileSize;
  334. if (_isDrag) //拖拽中
  335. {
  336. if (_activeArea != null)
  337. {
  338. //拖拽节点操作
  339. if (_activeArea.Direction == DoorDirection.N || _activeArea.Direction == DoorDirection.S)
  340. {
  341. if (_activePointType == 0)
  342. {
  343. var mouseOffset = Approach(mousePosition.X, tileSize.X);
  344. _activeArea.StartPosition = new Vector2(mouseOffset, _activeArea.StartPosition.Y);
  345. _activeArea.Start = mouseOffset - mapRect.Position.X;
  346. _dragHasCollision = _activeArea.StartPosition.X <= mapRect.Position.X ||
  347. _activeArea.StartPosition.X + 3 * tileSize.X >=
  348. _activeArea.EndPosition.X ||
  349. CheckDoorCollision(_activeArea.Direction, _activeArea);
  350. }
  351. else
  352. {
  353. var mouseOffset = Approach(mousePosition.X, tileSize.X);
  354. _activeArea.EndPosition = new Vector2(mouseOffset, _activeArea.EndPosition.Y);
  355. _activeArea.End = mouseOffset - mapRect.Position.X;
  356. _dragHasCollision = _activeArea.EndPosition.X >= mapRect.Position.X + mapRect.Size.X ||
  357. _activeArea.EndPosition.X - 3 * tileSize.X <=
  358. _activeArea.StartPosition.X ||
  359. CheckDoorCollision(_activeArea.Direction, _activeArea);
  360. }
  361. }
  362. else
  363. {
  364. if (_activePointType == 0)
  365. {
  366. var mouseOffset = Approach(mousePosition.Y, tileSize.Y);
  367. _activeArea.StartPosition = new Vector2(_activeArea.StartPosition.X, mouseOffset);
  368. _activeArea.Start = mouseOffset - mapRect.Position.Y;
  369. _dragHasCollision = _activeArea.StartPosition.Y <= mapRect.Position.Y ||
  370. _activeArea.StartPosition.Y + 3 * tileSize.Y >=
  371. _activeArea.EndPosition.Y ||
  372. CheckDoorCollision(_activeArea.Direction, _activeArea);
  373. }
  374. else
  375. {
  376. var mouseOffset = Approach(mousePosition.Y, tileSize.Y);
  377. _activeArea.EndPosition = new Vector2(_activeArea.EndPosition.X, mouseOffset);
  378. _activeArea.End = mouseOffset - mapRect.Position.Y;
  379. _dragHasCollision = _activeArea.EndPosition.Y >= mapRect.Position.Y + mapRect.Size.Y ||
  380. _activeArea.EndPosition.Y - 3 * tileSize.Y <=
  381. _activeArea.StartPosition.Y ||
  382. CheckDoorCollision(_activeArea.Direction, _activeArea);
  383. }
  384. }
  385. }
  386. }
  387. else
  388. {
  389. if (Mathf.Abs(mousePosition.Y - mapRect.Position.Y) <= 8 && mousePosition.X >= mapRect.Position.X &&
  390. mousePosition.X <= mapRect.Position.X + mapRect.Size.X) //上
  391. {
  392. _hover = true;
  393. _hoverDirection = DoorDirection.N;
  394. var mouseOffset = Approach(mousePosition.X, tileSize.X);
  395. _hoverPoint1 = new Vector2(mouseOffset - tileSize.X * 2, mapRect.Position.Y);
  396. _hoverPoint2 = new Vector2(_hoverPoint1.X + tileSize.X * 4, _hoverPoint1.Y);
  397.  
  398. //判断是否能放下新的门
  399. if (_hoverPoint1.X <= mapRect.Position.X ||
  400. _hoverPoint2.X >= mapRect.Position.X + mapRect.Size.X ||
  401. CheckDoorCollision())
  402. {
  403. _canPut = false;
  404. FindHoverPoint(mouseOffset);
  405. }
  406. else
  407. {
  408. _canPut = true;
  409. _hasActivePoint = false;
  410. _activeArea = null;
  411. }
  412. }
  413. else if (Mathf.Abs(mousePosition.X - mapRect.Position.X) <= 8 &&
  414. mousePosition.Y >= mapRect.Position.Y &&
  415. mousePosition.Y <= mapRect.Position.Y + mapRect.Size.Y) //左
  416. {
  417. _hover = true;
  418. _hoverDirection = DoorDirection.W;
  419. var mouseOffset = Approach(mousePosition.Y, tileSize.Y);
  420. _hoverPoint1 = new Vector2(mapRect.Position.X, mouseOffset - tileSize.Y * 2);
  421. _hoverPoint2 = new Vector2(_hoverPoint1.X, _hoverPoint1.Y + tileSize.X * 4);
  422.  
  423. //判断是否能放下新的门
  424. if (_hoverPoint1.Y <= mapRect.Position.Y ||
  425. _hoverPoint2.Y >= mapRect.Position.Y + mapRect.Size.Y ||
  426. CheckDoorCollision())
  427. {
  428. _canPut = false;
  429. FindHoverPoint(mouseOffset);
  430. }
  431. else
  432. {
  433. _canPut = true;
  434. _hasActivePoint = false;
  435. _activeArea = null;
  436. }
  437. }
  438. else if (Mathf.Abs(mousePosition.Y - (mapRect.Position.Y + mapRect.Size.Y)) <= 8 &&
  439. mousePosition.X >= mapRect.Position.X &&
  440. mousePosition.X <= mapRect.Position.X + mapRect.Size.X) //下
  441. {
  442. _hover = true;
  443. _hoverDirection = DoorDirection.S;
  444. var mouseOffset = Approach(mousePosition.X, tileSize.X);
  445. _hoverPoint1 = new Vector2(mouseOffset - tileSize.X * 2,
  446. mapRect.Position.Y + mapRect.Size.Y);
  447. _hoverPoint2 = new Vector2(_hoverPoint1.X + tileSize.X * 4, _hoverPoint1.Y);
  448.  
  449. //判断是否能放下新的门
  450. if (_hoverPoint1.X <= mapRect.Position.X ||
  451. _hoverPoint2.X >= mapRect.Position.X + mapRect.Size.X ||
  452. CheckDoorCollision())
  453. {
  454. _canPut = false;
  455. FindHoverPoint(mouseOffset);
  456. }
  457. else
  458. {
  459. _canPut = true;
  460. _hasActivePoint = false;
  461. _activeArea = null;
  462. }
  463. }
  464. else if (Mathf.Abs(mousePosition.X - (mapRect.Position.X + mapRect.Size.X)) <= 8 &&
  465. mousePosition.Y >= mapRect.Position.Y &&
  466. mousePosition.Y <= mapRect.Position.Y + mapRect.Size.Y) //右
  467. {
  468. _hover = true;
  469. _hoverDirection = DoorDirection.E;
  470. var mouseOffset = Approach(mousePosition.Y, tileSize.Y);
  471. _hoverPoint1 = new Vector2(mapRect.Position.X + mapRect.Size.X,
  472. mouseOffset - tileSize.Y * 2);
  473. _hoverPoint2 = new Vector2(_hoverPoint1.X, _hoverPoint1.Y + tileSize.X * 4);
  474.  
  475. //判断是否能放下新的门
  476. if (_hoverPoint1.Y <= mapRect.Position.Y ||
  477. _hoverPoint2.Y >= mapRect.Position.Y + mapRect.Size.Y ||
  478. CheckDoorCollision())
  479. {
  480. _canPut = false;
  481. FindHoverPoint(mouseOffset);
  482. }
  483. else
  484. {
  485. _canPut = true;
  486. _hasActivePoint = false;
  487. _activeArea = null;
  488. }
  489. }
  490. else
  491. {
  492. ClearState();
  493. }
  494. }
  495.  
  496. if (isClick && _canPut) //判断是否可以创建新的点
  497. {
  498. CreateDoorArea(mapRect);
  499. }
  500. else if (_mouseDown && !_isDrag) //拖拽节点
  501. {
  502. _isDrag = true;
  503. _dragHasCollision = false;
  504. if (_activeArea != null)
  505. {
  506. if (_activePointType == 0)
  507. {
  508. _startDragValue = _activeArea.Start;
  509. _startDragPositionValue = _activeArea.StartPosition;
  510. }
  511. else
  512. {
  513. _startDragValue = _activeArea.End;
  514. _startDragPositionValue = _activeArea.EndPosition;
  515. }
  516. }
  517. }
  518. else if (!_mouseDown && _isDrag) //松开拖拽的点
  519. {
  520. _isDrag = false;
  521. if (_activeArea != null) //提交拖拽结果
  522. {
  523. if (_dragHasCollision)
  524. {
  525. if (_activePointType == 0)
  526. {
  527. _activeArea.Start = _startDragValue;
  528. _activeArea.StartPosition = _startDragPositionValue;
  529. }
  530. else
  531. {
  532. _activeArea.End = _startDragValue;
  533. _activeArea.EndPosition = _startDragPositionValue;
  534. }
  535. }
  536.  
  537. //OnDoorAreaChange();
  538. }
  539.  
  540. _dragHasCollision = false;
  541. }
  542. }
  543. else
  544. {
  545. ClearState();
  546. }
  547.  
  548. _tileDrawHandler.QueueRedraw();
  549. }
  550. else
  551. {
  552. ClearState();
  553. }
  554.  
  555. //按下 ctrl + s 保存
  556. if (Input.IsKeyPressed(Key.Ctrl) && Input.IsKeyPressed(Key.S))
  557. {
  558. if (!_clickSave)
  559. {
  560. TriggerSave();
  561. }
  562. _clickSave = true;
  563. // if (_canSave)
  564. // {
  565. // _canSave = false;
  566. // TriggerSave();
  567. // }
  568. }
  569. else
  570. {
  571. _clickSave = false;
  572. }
  573. }
  574. private void ClearState()
  575. {
  576. _hover = false;
  577. _canPut = false;
  578. _hasActivePoint = false;
  579. _activeArea = null;
  580. }
  581.  
  582. private void OnTileChanged()
  583. {
  584. _calcTileNavTimer = 1f;
  585. }
  586. //创建门
  587. private void CreateDoorArea(Rect2 mapRect)
  588. {
  589. var doorAreaInfo = new DoorAreaInfo();
  590. doorAreaInfo.Direction = _hoverDirection;
  591. doorAreaInfo.StartPosition = _hoverPoint1;
  592. doorAreaInfo.EndPosition = _hoverPoint2;
  593. switch (_hoverDirection)
  594. {
  595. case DoorDirection.E:
  596. case DoorDirection.W:
  597. doorAreaInfo.Start = _hoverPoint1.Y - mapRect.Position.Y;
  598. doorAreaInfo.End = _hoverPoint2.Y - mapRect.Position.Y;
  599. break;
  600. case DoorDirection.N:
  601. case DoorDirection.S:
  602. doorAreaInfo.Start = _hoverPoint1.X - mapRect.Position.X;
  603. doorAreaInfo.End = _hoverPoint2.X - mapRect.Position.X;
  604. break;
  605. }
  606.  
  607. _dungeonRoomInfo.DoorAreaInfos.Add(doorAreaInfo);
  608. //OnDoorAreaChange();
  609. }
  610.  
  611. //移除门
  612. private void RemoveDoorArea(DoorAreaInfo doorAreaInfo)
  613. {
  614. _dungeonRoomInfo.DoorAreaInfos.Remove(doorAreaInfo);
  615. //OnDoorAreaChange();
  616. }
  617.  
  618. //检查门是否有碰撞
  619. private bool CheckDoorCollision()
  620. {
  621. foreach (var doorAreaInfo in _dungeonRoomInfo.DoorAreaInfos)
  622. {
  623. if (doorAreaInfo.Direction == _hoverDirection)
  624. {
  625. switch (_hoverDirection)
  626. {
  627. case DoorDirection.E:
  628. case DoorDirection.W:
  629. if (CheckValueCollision(doorAreaInfo.StartPosition.Y, doorAreaInfo.EndPosition.Y, _hoverPoint1.Y, _hoverPoint2.Y))
  630. {
  631. return true;
  632. }
  633. break;
  634. case DoorDirection.S:
  635. case DoorDirection.N:
  636. if (CheckValueCollision(doorAreaInfo.StartPosition.X, doorAreaInfo.EndPosition.X, _hoverPoint1.X, _hoverPoint2.X))
  637. {
  638. return true;
  639. }
  640. break;
  641. }
  642. }
  643. }
  644.  
  645. return false;
  646. }
  647.  
  648. //检查门是否有碰撞
  649. private bool CheckDoorCollision(DoorDirection direction, DoorAreaInfo info)
  650. {
  651. foreach (var doorAreaInfo in _dungeonRoomInfo.DoorAreaInfos)
  652. {
  653. if (doorAreaInfo.Direction == direction && info != doorAreaInfo &&
  654. CheckValueCollision(doorAreaInfo.Start, doorAreaInfo.End, info.Start, info.End))
  655. {
  656. return true;
  657. }
  658. }
  659.  
  660. return false;
  661. }
  662. private bool CheckValueCollision(float o1, float o2, float h1, float h2)
  663. {
  664. var size = TileSet.TileSize.X;
  665. return !(h2 < o1 - 3 * size || o2 + 3 * size < h1);
  666. }
  667.  
  668. private void FindHoverPoint(float mouseOffset)
  669. {
  670. if (_isDrag)
  671. {
  672. return;
  673. }
  674. //检测是否有碰撞的点
  675. var flag = false;
  676. foreach (var doorAreaInfo in _dungeonRoomInfo.DoorAreaInfos)
  677. {
  678. if (doorAreaInfo.Direction == _hoverDirection)
  679. {
  680. if (_hoverDirection == DoorDirection.N || _hoverDirection == DoorDirection.S)
  681. {
  682. if (Math.Abs(doorAreaInfo.StartPosition.X - mouseOffset) < 0.0001f)
  683. {
  684. _hasActivePoint = true;
  685. _activePointType = 0;
  686. _activeArea = doorAreaInfo;
  687. flag = true;
  688. break;
  689. }
  690. else if (Math.Abs(doorAreaInfo.EndPosition.X - mouseOffset) < 0.0001f)
  691. {
  692. _hasActivePoint = true;
  693. _activePointType = 1;
  694. _activeArea = doorAreaInfo;
  695. flag = true;
  696. break;
  697. }
  698. }
  699. else
  700. {
  701. if (Math.Abs(doorAreaInfo.StartPosition.Y - mouseOffset) < 0.0001f)
  702. {
  703. _hasActivePoint = true;
  704. _activePointType = 0;
  705. _activeArea = doorAreaInfo;
  706. flag = true;
  707. break;
  708. }
  709. else if (Math.Abs(doorAreaInfo.EndPosition.Y - mouseOffset) < 0.0001f)
  710. {
  711. _hasActivePoint = true;
  712. _activePointType = 1;
  713. _activeArea = doorAreaInfo;
  714. flag = true;
  715. break;
  716. }
  717. }
  718. }
  719. }
  720.  
  721. if (!flag)
  722. {
  723. _hasActivePoint = false;
  724. _activeArea = null;
  725. }
  726. }
  727.  
  728. private float Approach(float value, float period)
  729. {
  730. var temp = value % period;
  731. if (Mathf.Abs(temp) >= period / 2)
  732. {
  733. return ((int)(value / period) + (value >= 0 ? 1 : -1)) * period;
  734. }
  735.  
  736. return (int)(value / period) * period;
  737. }
  738.  
  739. //地图大小改变
  740. private void OnMapRectChange()
  741. {
  742. _dungeonRoomInfo.DoorAreaInfos.Clear();
  743. _canPut = false;
  744. _hasActivePoint = false;
  745. _activeArea = null;
  746. //OnDoorAreaChange();
  747. }
  748.  
  749. // //区域数据修改
  750. // private void OnDoorAreaChange()
  751. // {
  752. // _canSave = true;
  753. // }
  754.  
  755. //触发保存操作
  756. private void TriggerSave()
  757. {
  758. //如果没有找到对应的场景文件,则不保存
  759. var path = _dungeonRoomInfo.GroupName + "/" + DungeonRoomTypeToString(_dungeonRoomInfo.RoomType) + "/" + _dungeonRoomInfo.FileName;
  760. if (!File.Exists(GameConfig.RoomTileDir + path + ".tscn"))
  761. {
  762. return;
  763. }
  764. //计算导航网格
  765. _dungeonTile.GenerateNavigationPolygon(0);
  766. var polygonData = _dungeonTile.GetPolygonData();
  767. var rect = GetUsedRect();
  768. SaveConfig(_dungeonRoomInfo.DoorAreaInfos, rect.Position, rect.Size, polygonData.ToList(),
  769. _dungeonRoomInfo.GroupName, _dungeonRoomInfo.RoomType, Name);
  770. }
  771. /// <summary>
  772. /// 计算tile所占区域
  773. /// </summary>
  774. /// <returns></returns>
  775. public static Rect2 CalcTileRange(TileMap tileMap)
  776. {
  777. var usedRect = tileMap.GetUsedRect();
  778. var pos = usedRect.Position * tileMap.TileSet.TileSize;
  779. var size = usedRect.Size * tileMap.TileSet.TileSize;
  780. return new Rect2(tileMap.ToLocal(pos), size);
  781. }
  782. /// <summary>
  783. /// 保存房间配置
  784. /// </summary>
  785. public static void SaveConfig(List<DoorAreaInfo> doorConfigs, Vector2I position, Vector2I size, List<NavigationPolygonData> polygonData, string groupName, DungeonRoomType roomType, string fileName)
  786. {
  787. //存入本地
  788. var path = GameConfig.RoomTileDataDir + groupName + "/" + DungeonRoomTypeToString(roomType);
  789. if (!Directory.Exists(path))
  790. {
  791. Directory.CreateDirectory(path);
  792. }
  793.  
  794. var roomInfo = new DungeonRoomInfo();
  795. roomInfo.Position = new SerializeVector2(position);
  796. roomInfo.Size = new SerializeVector2(size);
  797. roomInfo.DoorAreaInfos = doorConfigs;
  798. roomInfo.NavigationList = polygonData;
  799. roomInfo.RoomType = roomType;
  800. roomInfo.GroupName = groupName;
  801. roomInfo.FileName = fileName;
  802. var config = new JsonSerializerOptions();
  803. config.WriteIndented = true;
  804. path += "/" + fileName + ".json";
  805. var jsonStr = JsonSerializer.Serialize(roomInfo, config);
  806. File.WriteAllText(path, jsonStr);
  807. GD.Print("保存房间配置成功!路径为:" + path);
  808. }
  809.  
  810. /// <summary>
  811. /// 读取房间配置
  812. /// </summary>
  813. private void ReadConfig(Rect2 mapRect, string name)
  814. {
  815. var path = GameConfig.RoomTileDataDir + name + ".json";
  816.  
  817. if (File.Exists(path))
  818. {
  819. var text = File.ReadAllText(path);
  820. try
  821. {
  822. _dungeonRoomInfo = DeserializeDungeonRoomInfo(text);
  823. //填充 StartPosition 和 EndPosition 数据
  824. foreach (var doorAreaInfo in _dungeonRoomInfo.DoorAreaInfos)
  825. {
  826. doorAreaInfo.CalcPosition(mapRect.Position, mapRect.Size);
  827. }
  828. }
  829. catch (Exception e)
  830. {
  831. GD.PrintErr($"加载房间数据'{path}'发生异常: " + e);
  832. }
  833. }
  834. }
  835.  
  836. /// <summary>
  837. /// 反序列化 DungeonRoomInfo
  838. /// </summary>
  839. public static DungeonRoomInfo DeserializeDungeonRoomInfo(string text)
  840. {
  841. // 下面这句代码在 Godot4.0_rc2的编辑器模式下, 重载脚本会导致编辑器一直报错!, 所以暂时先用下面的方法
  842. //var roomInfo = JsonSerializer.Deserialize<DungeonRoomInfo>(text);
  843.  
  844. var obj = Json.ParseString(text).AsGodotDictionary();
  845. var roomInfo = new DungeonRoomInfo();
  846. if (obj.ContainsKey("Position"))
  847. {
  848. var position = obj["Position"].AsGodotDictionary();
  849. roomInfo.Position = new SerializeVector2(position["X"].AsInt32(), position["Y"].AsInt32());
  850. }
  851.  
  852. if (obj.ContainsKey("Size"))
  853. {
  854. var size = obj["Size"].AsGodotDictionary();
  855. roomInfo.Size = new SerializeVector2(size["X"].AsInt32(), size["Y"].AsInt32());
  856. }
  857.  
  858. if (obj.ContainsKey("RoomType"))
  859. {
  860. var roomType = obj["RoomType"].AsInt32();
  861. roomInfo.RoomType = (DungeonRoomType)roomType;
  862. }
  863. if (obj.ContainsKey("GroupName"))
  864. {
  865. roomInfo.GroupName = obj["GroupName"].AsString();
  866. }
  867. if (obj.ContainsKey("FileName"))
  868. {
  869. roomInfo.FileName = obj["FileName"].AsString();
  870. }
  871.  
  872. if (obj.ContainsKey("DoorAreaInfos"))
  873. {
  874. var doorAreaInfos = obj["DoorAreaInfos"].AsGodotArray<Variant>();
  875. roomInfo.DoorAreaInfos = new List<DoorAreaInfo>();
  876. foreach (var item in doorAreaInfos)
  877. {
  878. var temp = item.AsGodotDictionary();
  879. var doorInfo = new DoorAreaInfo();
  880. doorInfo.Direction = (DoorDirection)temp["Direction"].AsInt32();
  881. doorInfo.Start = temp["Start"].AsInt32();
  882. doorInfo.End = temp["End"].AsInt32();
  883. roomInfo.DoorAreaInfos.Add(doorInfo);
  884. }
  885. }
  886.  
  887. if (obj.ContainsKey("NavigationList"))
  888. {
  889. var navigationArray = obj["NavigationList"].AsGodotArray<Variant>();
  890. roomInfo.NavigationList = new List<NavigationPolygonData>();
  891. for (var i = 0; i < navigationArray.Count; i++)
  892. {
  893. var navigation = navigationArray[i].AsGodotDictionary();
  894. var polygonData = new NavigationPolygonData();
  895.  
  896. polygonData.Type = (NavigationPolygonType)navigation["Type"].AsInt32();
  897. polygonData.Points = new List<SerializeVector2>();
  898. var pointArray = navigation["Points"].AsGodotArray<Variant>();
  899. for (var j = 0; j < pointArray.Count; j++)
  900. {
  901. var point = pointArray[j].AsGodotDictionary();
  902. polygonData.Points.Add(new SerializeVector2(point["X"].AsInt32(), point["Y"].AsInt32()));
  903. }
  904.  
  905. roomInfo.NavigationList.Add(polygonData);
  906. }
  907. }
  908.  
  909. return roomInfo;
  910. }
  911. /// <summary>
  912. /// 将房间类型枚举转为字符串
  913. /// </summary>
  914. public static string DungeonRoomTypeToString(DungeonRoomType roomType)
  915. {
  916. switch (roomType)
  917. {
  918. case DungeonRoomType.Battle: return "battle";
  919. case DungeonRoomType.Inlet: return "inlet";
  920. case DungeonRoomType.Outlet: return "outlet";
  921. case DungeonRoomType.Boss: return "boss";
  922. case DungeonRoomType.Reward: return "reward";
  923. case DungeonRoomType.Shop: return "shop";
  924. case DungeonRoomType.Event: return "event";
  925. }
  926.  
  927. return "battle";
  928. }
  929. /// <summary>
  930. /// 将房间类型枚举转为描述字符串
  931. /// </summary>
  932. public static string DungeonRoomTypeToDescribeString(DungeonRoomType roomType)
  933. {
  934. switch (roomType)
  935. {
  936. case DungeonRoomType.Battle: return "战斗房间";
  937. case DungeonRoomType.Inlet: return "起始房间";
  938. case DungeonRoomType.Outlet: return "结束房间";
  939. case DungeonRoomType.Boss: return "boss战房间";
  940. case DungeonRoomType.Reward: return "奖励房间";
  941. case DungeonRoomType.Shop: return "商店房间";
  942. case DungeonRoomType.Event: return "事件房间";
  943. }
  944.  
  945. return "战斗房间";
  946. }
  947. #endif
  948.  
  949. /// <summary>
  950. /// 获取所有标记数据
  951. /// </summary>
  952. public ActivityMark[] GetMarks()
  953. {
  954. var list = new List<ActivityMark>();
  955. foreach (var child in GetChildren())
  956. {
  957. EachAndGetMarks(child, list);
  958. }
  959.  
  960. return list.ToArray();
  961. }
  962.  
  963. private void EachAndGetMarks(Node node, List<ActivityMark> list)
  964. {
  965. if (node is ActivityMark mark)
  966. {
  967. list.Add(mark);
  968. }
  969. foreach (var child in node.GetChildren())
  970. {
  971. EachAndGetMarks(child, list);
  972. }
  973. }
  974. }