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