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. //拖拽
  34. private bool _isDrag = false;
  35. private float _startDragValue;
  36. private Vector2 _startDragPositionValue;
  37. private bool _dragHasCollision = false;
  38.  
  39. private bool _mouseDown = false;
  40.  
  41. //门区域数据
  42. private List<DoorAreaInfo> _doorConfigs;
  43. private Rect2 _prevRect;
  44.  
  45. //是否能保存
  46. private bool _canSave = false;
  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._doorConfigs != null)
  115. {
  116. var color2 = new Color(0, 1, 0, 0.8f);
  117. //绘制已经存在的
  118. foreach (var doorAreaInfo in RoomTemplate._doorConfigs)
  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 (_doorConfigs == null)
  280. {
  281. initConfigs = true;
  282. _doorConfigs = ReadConfig(CalcTileRange(this), Name);
  283. }
  284.  
  285. //按键检测
  286. var isClick = false;
  287. if (Input.IsMouseButtonPressed(MouseButton.Left))
  288. {
  289. if (!_mouseDown)
  290. {
  291. _mouseDown = true;
  292. isClick = true;
  293. }
  294. }
  295. else if (_mouseDown)
  296. {
  297. _mouseDown = false;
  298. isClick = false;
  299. }
  300.  
  301. if (Input.IsMouseButtonPressed(MouseButton.Middle)) //中键移除门
  302. {
  303. if (EnableEdit && _activeArea != null)
  304. {
  305. RemoveDoorArea(_activeArea);
  306. _hasActivePoint = false;
  307. _activeArea = null;
  308. }
  309. }
  310. else if (TileSet != null) //编辑操作
  311. {
  312. var mapRect = CalcTileRange(this);
  313. var mousePosition = GetLocalMousePosition();
  314.  
  315. if (mapRect != _prevRect)
  316. {
  317. if (!initConfigs)
  318. {
  319. OnMapRectChange();
  320. }
  321. }
  322.  
  323. _prevRect = mapRect;
  324. if (EnableEdit)
  325. {
  326. var tileSize = TileSet.TileSize;
  327. if (_isDrag) //拖拽中
  328. {
  329. if (_activeArea != null)
  330. {
  331. //拖拽节点操作
  332. if (_activeArea.Direction == DoorDirection.N || _activeArea.Direction == DoorDirection.S)
  333. {
  334. if (_activePointType == 0)
  335. {
  336. var mouseOffset = Approach(mousePosition.X, tileSize.X);
  337. _activeArea.StartPosition = new Vector2(mouseOffset, _activeArea.StartPosition.Y);
  338. _activeArea.Start = mouseOffset - mapRect.Position.X;
  339. _dragHasCollision = _activeArea.StartPosition.X <= mapRect.Position.X ||
  340. _activeArea.StartPosition.X + 3 * tileSize.X >=
  341. _activeArea.EndPosition.X ||
  342. CheckDoorCollision(_activeArea.Direction, _activeArea);
  343. }
  344. else
  345. {
  346. var mouseOffset = Approach(mousePosition.X, tileSize.X);
  347. _activeArea.EndPosition = new Vector2(mouseOffset, _activeArea.EndPosition.Y);
  348. _activeArea.End = mouseOffset - mapRect.Position.X;
  349. _dragHasCollision = _activeArea.EndPosition.X >= mapRect.Position.X + mapRect.Size.X ||
  350. _activeArea.EndPosition.X - 3 * tileSize.X <=
  351. _activeArea.StartPosition.X ||
  352. CheckDoorCollision(_activeArea.Direction, _activeArea);
  353. }
  354. }
  355. else
  356. {
  357. if (_activePointType == 0)
  358. {
  359. var mouseOffset = Approach(mousePosition.Y, tileSize.Y);
  360. _activeArea.StartPosition = new Vector2(_activeArea.StartPosition.X, mouseOffset);
  361. _activeArea.Start = mouseOffset - mapRect.Position.Y;
  362. _dragHasCollision = _activeArea.StartPosition.Y <= mapRect.Position.Y ||
  363. _activeArea.StartPosition.Y + 3 * tileSize.Y >=
  364. _activeArea.EndPosition.Y ||
  365. CheckDoorCollision(_activeArea.Direction, _activeArea);
  366. }
  367. else
  368. {
  369. var mouseOffset = Approach(mousePosition.Y, tileSize.Y);
  370. _activeArea.EndPosition = new Vector2(_activeArea.EndPosition.X, mouseOffset);
  371. _activeArea.End = mouseOffset - mapRect.Position.Y;
  372. _dragHasCollision = _activeArea.EndPosition.Y >= mapRect.Position.Y + mapRect.Size.Y ||
  373. _activeArea.EndPosition.Y - 3 * tileSize.Y <=
  374. _activeArea.StartPosition.Y ||
  375. CheckDoorCollision(_activeArea.Direction, _activeArea);
  376. }
  377. }
  378. }
  379. }
  380. else
  381. {
  382. if (Mathf.Abs(mousePosition.Y - mapRect.Position.Y) <= 8 && mousePosition.X >= mapRect.Position.X &&
  383. mousePosition.X <= mapRect.Position.X + mapRect.Size.X) //上
  384. {
  385. _hover = true;
  386. _hoverDirection = DoorDirection.N;
  387. var mouseOffset = Approach(mousePosition.X, tileSize.X);
  388. _hoverPoint1 = new Vector2(mouseOffset - tileSize.X * 2, mapRect.Position.Y);
  389. _hoverPoint2 = new Vector2(_hoverPoint1.X + tileSize.X * 4, _hoverPoint1.Y);
  390.  
  391. //判断是否能放下新的门
  392. if (_hoverPoint1.X <= mapRect.Position.X ||
  393. _hoverPoint2.X >= mapRect.Position.X + mapRect.Size.X ||
  394. CheckDoorCollision())
  395. {
  396. _canPut = false;
  397. FindHoverPoint(mouseOffset);
  398. }
  399. else
  400. {
  401. _canPut = true;
  402. _hasActivePoint = false;
  403. _activeArea = null;
  404. }
  405. }
  406. else if (Mathf.Abs(mousePosition.X - mapRect.Position.X) <= 8 &&
  407. mousePosition.Y >= mapRect.Position.Y &&
  408. mousePosition.Y <= mapRect.Position.Y + mapRect.Size.Y) //左
  409. {
  410. _hover = true;
  411. _hoverDirection = DoorDirection.W;
  412. var mouseOffset = Approach(mousePosition.Y, tileSize.Y);
  413. _hoverPoint1 = new Vector2(mapRect.Position.X, mouseOffset - tileSize.Y * 2);
  414. _hoverPoint2 = new Vector2(_hoverPoint1.X, _hoverPoint1.Y + tileSize.X * 4);
  415.  
  416. //判断是否能放下新的门
  417. if (_hoverPoint1.Y <= mapRect.Position.Y ||
  418. _hoverPoint2.Y >= mapRect.Position.Y + mapRect.Size.Y ||
  419. CheckDoorCollision())
  420. {
  421. _canPut = false;
  422. FindHoverPoint(mouseOffset);
  423. }
  424. else
  425. {
  426. _canPut = true;
  427. _hasActivePoint = false;
  428. _activeArea = null;
  429. }
  430. }
  431. else if (Mathf.Abs(mousePosition.Y - (mapRect.Position.Y + mapRect.Size.Y)) <= 8 &&
  432. mousePosition.X >= mapRect.Position.X &&
  433. mousePosition.X <= mapRect.Position.X + mapRect.Size.X) //下
  434. {
  435. _hover = true;
  436. _hoverDirection = DoorDirection.S;
  437. var mouseOffset = Approach(mousePosition.X, tileSize.X);
  438. _hoverPoint1 = new Vector2(mouseOffset - tileSize.X * 2,
  439. mapRect.Position.Y + mapRect.Size.Y);
  440. _hoverPoint2 = new Vector2(_hoverPoint1.X + tileSize.X * 4, _hoverPoint1.Y);
  441.  
  442. //判断是否能放下新的门
  443. if (_hoverPoint1.X <= mapRect.Position.X ||
  444. _hoverPoint2.X >= mapRect.Position.X + mapRect.Size.X ||
  445. CheckDoorCollision())
  446. {
  447. _canPut = false;
  448. FindHoverPoint(mouseOffset);
  449. }
  450. else
  451. {
  452. _canPut = true;
  453. _hasActivePoint = false;
  454. _activeArea = null;
  455. }
  456. }
  457. else if (Mathf.Abs(mousePosition.X - (mapRect.Position.X + mapRect.Size.X)) <= 8 &&
  458. mousePosition.Y >= mapRect.Position.Y &&
  459. mousePosition.Y <= mapRect.Position.Y + mapRect.Size.Y) //右
  460. {
  461. _hover = true;
  462. _hoverDirection = DoorDirection.E;
  463. var mouseOffset = Approach(mousePosition.Y, tileSize.Y);
  464. _hoverPoint1 = new Vector2(mapRect.Position.X + mapRect.Size.X,
  465. mouseOffset - tileSize.Y * 2);
  466. _hoverPoint2 = new Vector2(_hoverPoint1.X, _hoverPoint1.Y + tileSize.X * 4);
  467.  
  468. //判断是否能放下新的门
  469. if (_hoverPoint1.Y <= mapRect.Position.Y ||
  470. _hoverPoint2.Y >= mapRect.Position.Y + mapRect.Size.Y ||
  471. CheckDoorCollision())
  472. {
  473. _canPut = false;
  474. FindHoverPoint(mouseOffset);
  475. }
  476. else
  477. {
  478. _canPut = true;
  479. _hasActivePoint = false;
  480. _activeArea = null;
  481. }
  482. }
  483. else
  484. {
  485. ClearState();
  486. }
  487. }
  488.  
  489. if (isClick && _canPut) //判断是否可以创建新的点
  490. {
  491. CreateDoorArea(mapRect);
  492. }
  493. else if (_mouseDown && !_isDrag) //拖拽节点
  494. {
  495. _isDrag = true;
  496. _dragHasCollision = false;
  497. if (_activeArea != null)
  498. {
  499. if (_activePointType == 0)
  500. {
  501. _startDragValue = _activeArea.Start;
  502. _startDragPositionValue = _activeArea.StartPosition;
  503. }
  504. else
  505. {
  506. _startDragValue = _activeArea.End;
  507. _startDragPositionValue = _activeArea.EndPosition;
  508. }
  509. }
  510. }
  511. else if (!_mouseDown && _isDrag) //松开拖拽的点
  512. {
  513. _isDrag = false;
  514. if (_activeArea != null) //提交拖拽结果
  515. {
  516. if (_dragHasCollision)
  517. {
  518. if (_activePointType == 0)
  519. {
  520. _activeArea.Start = _startDragValue;
  521. _activeArea.StartPosition = _startDragPositionValue;
  522. }
  523. else
  524. {
  525. _activeArea.End = _startDragValue;
  526. _activeArea.EndPosition = _startDragPositionValue;
  527. }
  528. }
  529.  
  530. OnDoorAreaChange();
  531. }
  532.  
  533. _dragHasCollision = false;
  534. }
  535. }
  536. else
  537. {
  538. ClearState();
  539. }
  540.  
  541. _tileDrawHandler.QueueRedraw();
  542. }
  543. else
  544. {
  545. ClearState();
  546. }
  547.  
  548. //按下 ctrl + s 保存
  549. if (Input.IsKeyPressed(Key.Ctrl) && Input.IsKeyPressed(Key.S))
  550. {
  551. _clickSave = true;
  552. if (_canSave)
  553. {
  554. _canSave = false;
  555. TriggerSave();
  556. }
  557. }
  558. else
  559. {
  560. _clickSave = false;
  561. }
  562. }
  563. private void ClearState()
  564. {
  565. _hover = false;
  566. _canPut = false;
  567. _hasActivePoint = false;
  568. _activeArea = null;
  569. }
  570.  
  571. private void OnTileChanged()
  572. {
  573. _calcTileNavTimer = 1f;
  574. }
  575. //创建门
  576. private void CreateDoorArea(Rect2 mapRect)
  577. {
  578. var doorAreaInfo = new DoorAreaInfo();
  579. doorAreaInfo.Direction = _hoverDirection;
  580. doorAreaInfo.StartPosition = _hoverPoint1;
  581. doorAreaInfo.EndPosition = _hoverPoint2;
  582. switch (_hoverDirection)
  583. {
  584. case DoorDirection.E:
  585. case DoorDirection.W:
  586. doorAreaInfo.Start = _hoverPoint1.Y - mapRect.Position.Y;
  587. doorAreaInfo.End = _hoverPoint2.Y - mapRect.Position.Y;
  588. break;
  589. case DoorDirection.N:
  590. case DoorDirection.S:
  591. doorAreaInfo.Start = _hoverPoint1.X - mapRect.Position.X;
  592. doorAreaInfo.End = _hoverPoint2.X - mapRect.Position.X;
  593. break;
  594. }
  595.  
  596. _doorConfigs.Add(doorAreaInfo);
  597. OnDoorAreaChange();
  598. }
  599.  
  600. //移除门
  601. private void RemoveDoorArea(DoorAreaInfo doorAreaInfo)
  602. {
  603. _doorConfigs.Remove(doorAreaInfo);
  604. OnDoorAreaChange();
  605. }
  606.  
  607. //检查门是否有碰撞
  608. private bool CheckDoorCollision()
  609. {
  610. foreach (var doorAreaInfo in _doorConfigs)
  611. {
  612. if (doorAreaInfo.Direction == _hoverDirection)
  613. {
  614. switch (_hoverDirection)
  615. {
  616. case DoorDirection.E:
  617. case DoorDirection.W:
  618. if (CheckValueCollision(doorAreaInfo.StartPosition.Y, doorAreaInfo.EndPosition.Y, _hoverPoint1.Y, _hoverPoint2.Y))
  619. {
  620. return true;
  621. }
  622. break;
  623. case DoorDirection.S:
  624. case DoorDirection.N:
  625. if (CheckValueCollision(doorAreaInfo.StartPosition.X, doorAreaInfo.EndPosition.X, _hoverPoint1.X, _hoverPoint2.X))
  626. {
  627. return true;
  628. }
  629. break;
  630. }
  631. }
  632. }
  633.  
  634. return false;
  635. }
  636.  
  637. //检查门是否有碰撞
  638. private bool CheckDoorCollision(DoorDirection direction, DoorAreaInfo info)
  639. {
  640. foreach (var doorAreaInfo in _doorConfigs)
  641. {
  642. if (doorAreaInfo.Direction == direction && info != doorAreaInfo &&
  643. CheckValueCollision(doorAreaInfo.Start, doorAreaInfo.End, info.Start, info.End))
  644. {
  645. return true;
  646. }
  647. }
  648.  
  649. return false;
  650. }
  651. private bool CheckValueCollision(float o1, float o2, float h1, float h2)
  652. {
  653. var size = TileSet.TileSize.X;
  654. return !(h2 < o1 - 3 * size || o2 + 3 * size < h1);
  655. }
  656.  
  657. private void FindHoverPoint(float mouseOffset)
  658. {
  659. if (_isDrag)
  660. {
  661. return;
  662. }
  663. //检测是否有碰撞的点
  664. var flag = false;
  665. foreach (var doorAreaInfo in _doorConfigs)
  666. {
  667. if (doorAreaInfo.Direction == _hoverDirection)
  668. {
  669. if (_hoverDirection == DoorDirection.N || _hoverDirection == DoorDirection.S)
  670. {
  671. if (Math.Abs(doorAreaInfo.StartPosition.X - mouseOffset) < 0.0001f)
  672. {
  673. _hasActivePoint = true;
  674. _activePointType = 0;
  675. _activeArea = doorAreaInfo;
  676. flag = true;
  677. break;
  678. }
  679. else if (Math.Abs(doorAreaInfo.EndPosition.X - mouseOffset) < 0.0001f)
  680. {
  681. _hasActivePoint = true;
  682. _activePointType = 1;
  683. _activeArea = doorAreaInfo;
  684. flag = true;
  685. break;
  686. }
  687. }
  688. else
  689. {
  690. if (Math.Abs(doorAreaInfo.StartPosition.Y - mouseOffset) < 0.0001f)
  691. {
  692. _hasActivePoint = true;
  693. _activePointType = 0;
  694. _activeArea = doorAreaInfo;
  695. flag = true;
  696. break;
  697. }
  698. else if (Math.Abs(doorAreaInfo.EndPosition.Y - mouseOffset) < 0.0001f)
  699. {
  700. _hasActivePoint = true;
  701. _activePointType = 1;
  702. _activeArea = doorAreaInfo;
  703. flag = true;
  704. break;
  705. }
  706. }
  707. }
  708. }
  709.  
  710. if (!flag)
  711. {
  712. _hasActivePoint = false;
  713. _activeArea = null;
  714. }
  715. }
  716.  
  717. private float Approach(float value, float period)
  718. {
  719. var temp = value % period;
  720. if (Mathf.Abs(temp) >= period / 2)
  721. {
  722. return ((int)(value / period) + (value >= 0 ? 1 : -1)) * period;
  723. }
  724.  
  725. return (int)(value / period) * period;
  726. }
  727.  
  728. //地图大小改变
  729. private void OnMapRectChange()
  730. {
  731. _doorConfigs.Clear();
  732. _canPut = false;
  733. _hasActivePoint = false;
  734. _activeArea = null;
  735. OnDoorAreaChange();
  736. }
  737.  
  738. //区域数据修改
  739. private void OnDoorAreaChange()
  740. {
  741. _canSave = true;
  742. }
  743.  
  744. //触发保存操作
  745. private void TriggerSave()
  746. {
  747. //如果没有找到对应的场景文件,则不保存
  748. if (!File.Exists(GameConfig.RoomTileDir + Name + ".tscn"))
  749. {
  750. return;
  751. }
  752. //计算导航网格
  753. _dungeonTile.GenerateNavigationPolygon(0);
  754. var polygonData = _dungeonTile.GetPolygonData();
  755. var rect = GetUsedRect();
  756. SaveConfig(_doorConfigs, rect.Position, rect.Size, polygonData.ToList(), Name);
  757. }
  758. /// <summary>
  759. /// 计算tile所占区域
  760. /// </summary>
  761. /// <returns></returns>
  762. public static Rect2 CalcTileRange(TileMap tileMap)
  763. {
  764. var usedRect = tileMap.GetUsedRect();
  765. var pos = usedRect.Position * tileMap.TileSet.TileSize;
  766. var size = usedRect.Size * tileMap.TileSet.TileSize;
  767. return new Rect2(tileMap.ToLocal(pos), size);
  768. }
  769. /// <summary>
  770. /// 保存房间配置
  771. /// </summary>
  772. public static void SaveConfig(List<DoorAreaInfo> doorConfigs, Vector2I position, Vector2I size, List<NavigationPolygonData> polygonData, string name)
  773. {
  774. //存入本地
  775. var path = GameConfig.RoomTileDataDir + name + ".json";
  776. var roomInfo = new DungeonRoomInfo();
  777. roomInfo.Position = new SerializeVector2(position);
  778. roomInfo.Size = new SerializeVector2(size);
  779. roomInfo.DoorAreaInfos = doorConfigs;
  780. roomInfo.NavigationList = polygonData;
  781. var config = new JsonSerializerOptions();
  782. config.WriteIndented = true;
  783. var jsonStr = JsonSerializer.Serialize(roomInfo, config);
  784. File.WriteAllText(path, jsonStr);
  785. GD.Print("保存房间配置成功!路径为:" + path);
  786. }
  787. /// <summary>
  788. /// 读取房间配置
  789. /// </summary>
  790. public static List<DoorAreaInfo> ReadConfig(Rect2 mapRect, string name)
  791. {
  792. var path = GameConfig.RoomTileDataDir + name + ".json";
  793. if (File.Exists(path))
  794. {
  795. var text = File.ReadAllText(path);
  796. try
  797. {
  798. var roomInfo = DeserializeDungeonRoomInfo(text);
  799. //填充 StartPosition 和 EndPosition 数据
  800. foreach (var doorAreaInfo in roomInfo.DoorAreaInfos)
  801. {
  802. doorAreaInfo.CalcPosition(mapRect.Position, mapRect.Size);
  803. }
  804. return roomInfo.DoorAreaInfos;
  805. }
  806. catch (Exception e)
  807. {
  808. GD.PrintErr($"加载房间数据'{path}'发生异常: " + e);
  809. return new List<DoorAreaInfo>();
  810. }
  811. }
  812. else
  813. {
  814. return new List<DoorAreaInfo>();
  815. }
  816. }
  817.  
  818. /// <summary>
  819. /// 反序列化 DungeonRoomInfo
  820. /// </summary>
  821. public static DungeonRoomInfo DeserializeDungeonRoomInfo(string text)
  822. {
  823. // 下面这句代码在 Godot4.0_rc2的编辑器模式下, 重载脚本会导致编辑器一直报错!, 所以暂时先用下面的方法
  824. //var roomInfo = JsonSerializer.Deserialize<DungeonRoomInfo>(text);
  825.  
  826. var obj = Json.ParseString(text).AsGodotDictionary();
  827. var roomInfo = new DungeonRoomInfo();
  828. var position = obj["Position"].AsGodotDictionary();
  829. roomInfo.Position = new SerializeVector2(position["X"].AsInt32(), position["Y"].AsInt32());
  830.  
  831. var size = obj["Size"].AsGodotDictionary();
  832. roomInfo.Size = new SerializeVector2(size["X"].AsInt32(), size["Y"].AsInt32());
  833.  
  834. var doorAreaInfos = obj["DoorAreaInfos"].AsGodotArray<Variant>();
  835. roomInfo.DoorAreaInfos = new List<DoorAreaInfo>();
  836. foreach (var item in doorAreaInfos)
  837. {
  838. var temp = item.AsGodotDictionary();
  839. var doorInfo = new DoorAreaInfo();
  840. doorInfo.Direction = (DoorDirection)temp["Direction"].AsInt32();
  841. doorInfo.Start = temp["Start"].AsInt32();
  842. doorInfo.End = temp["End"].AsInt32();
  843. roomInfo.DoorAreaInfos.Add(doorInfo);
  844. }
  845.  
  846. var navigationArray = obj["NavigationList"].AsGodotArray<Variant>();
  847. roomInfo.NavigationList = new List<NavigationPolygonData>();
  848. for (var i = 0; i < navigationArray.Count; i++)
  849. {
  850. var navigation = navigationArray[i].AsGodotDictionary();
  851. var polygonData = new NavigationPolygonData();
  852.  
  853. polygonData.Type = (NavigationPolygonType)navigation["Type"].AsInt32();
  854. polygonData.Points = new List<SerializeVector2>();
  855. var pointArray = navigation["Points"].AsGodotArray<Variant>();
  856. for (var j = 0; j < pointArray.Count; j++)
  857. {
  858. var point = pointArray[j].AsGodotDictionary();
  859. polygonData.Points.Add(new SerializeVector2(point["X"].AsInt32(), point["Y"].AsInt32()));
  860. }
  861.  
  862. roomInfo.NavigationList.Add(polygonData);
  863. }
  864.  
  865. return roomInfo;
  866. }
  867. #endif
  868.  
  869. /// <summary>
  870. /// 获取所有标记数据
  871. /// </summary>
  872. public ActivityMark[] GetMarks()
  873. {
  874. var list = new List<ActivityMark>();
  875. foreach (var child in GetChildren())
  876. {
  877. EachAndGetMarks(child, list);
  878. }
  879.  
  880. return list.ToArray();
  881. }
  882.  
  883. private void EachAndGetMarks(Node node, List<ActivityMark> list)
  884. {
  885. if (node is ActivityMark mark)
  886. {
  887. list.Add(mark);
  888. }
  889. foreach (var child in node.GetChildren())
  890. {
  891. EachAndGetMarks(child, list);
  892. }
  893. }
  894. }