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