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