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