Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / room / RoomManager.cs
@小李xl 小李xl on 23 Nov 2022 21 KB 自动计算ai可移动区域
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using Godot;
  5.  
  6. /// <summary>
  7. /// 房间管理器
  8. /// </summary>
  9. public class RoomManager : Navigation2D
  10. {
  11. /// <summary>
  12. /// 玩家对象
  13. /// </summary>
  14. public Role Player { get; private set; }
  15.  
  16. //对象根节点
  17. private Node2D _objectRoot;
  18.  
  19. //对象根节点, 带y轴排序功能
  20. private YSort _sortRoot;
  21.  
  22. private Node2D _mapRoot;
  23.  
  24. private NavigationPolygonInstance _navigationPolygon;
  25. private Enemy _enemy;
  26.  
  27. //可行走区域的tileId
  28. private List<int> _wayIds = new List<int>(new[] { 129 });
  29.  
  30. //已经标记过的点
  31. private HashSet<Vector2> _usePoints = new HashSet<Vector2>();
  32.  
  33. //导航区域数据
  34. private List<NavigationPolygonData> _polygonDataList = new List<NavigationPolygonData>();
  35.  
  36. public override void _EnterTree()
  37. {
  38. Input.MouseMode = Input.MouseModeEnum.Hidden;
  39.  
  40. _sortRoot = GetNode<YSort>("SortRoot");
  41. _objectRoot = GetNode<Node2D>("ObjectRoot");
  42.  
  43. _navigationPolygon = GetNode<NavigationPolygonInstance>("NavigationPolygonInstance");
  44.  
  45. //初始化地图
  46. _mapRoot = GetNode<Node2D>("MapRoot");
  47. var node = _mapRoot.GetChild(0).GetNode("Config");
  48. Color color = (Color)node.GetMeta("ClearColor");
  49. VisualServer.SetDefaultClearColor(color);
  50.  
  51. //创建玩家
  52. Player = new Player();
  53. Player.Position = new Vector2(100, 100);
  54. Player.Name = "Player";
  55. Player.PutDown();
  56.  
  57. _enemy = new Enemy();
  58. _enemy.Name = "Enemy";
  59. _enemy.PutDown(new Vector2(150, 150));
  60. }
  61.  
  62. public override void _Ready()
  63. {
  64. GenerateNavigationPolygon();
  65.  
  66. //播放bgm
  67. SoundManager.PlayMusic(ResourcePath.resource_sound_bgm_Intro_ogg, -17f);
  68. _enemy.PickUpWeapon(WeaponManager.GetGun("1001"));
  69.  
  70. WeaponManager.GetGun("1001").PutDown(new Vector2(80, 100));
  71. WeaponManager.GetGun("1001").PutDown(new Vector2(80, 80));
  72. WeaponManager.GetGun("1002").PutDown(new Vector2(80, 120));
  73. WeaponManager.GetGun("1003").PutDown(new Vector2(120, 80));
  74.  
  75. WeaponManager.GetGun("1003").PutDown(new Vector2(180, 80));
  76. WeaponManager.GetGun("1003").PutDown(new Vector2(180, 180));
  77. WeaponManager.GetGun("1002").PutDown(new Vector2(180, 120));
  78.  
  79. WeaponManager.GetGun("1004").PutDown(new Vector2(220, 120));
  80. }
  81.  
  82. public override void _Process(float delta)
  83. {
  84. if (GameApplication.Instance.Debug)
  85. {
  86. Update();
  87. }
  88. }
  89.  
  90. public override void _Draw()
  91. {
  92. if (GameApplication.Instance.Debug)
  93. {
  94. for (var i = 0; i < _polygonDataList.Count; i++)
  95. {
  96. var item = _polygonDataList[i];
  97. if (item.Points.Count >= 2)
  98. {
  99. DrawPolyline(item.Points.ToArray(), Colors.Red);
  100. }
  101. }
  102. }
  103. }
  104.  
  105. /// <summary>
  106. /// 获取房间根节点
  107. /// </summary>
  108. /// <param name="useYSort">是否获取 YSort 节点</param>
  109. /// <returns></returns>
  110. public Node2D GetRoot(bool useYSort = false)
  111. {
  112. return useYSort ? _sortRoot : _objectRoot;
  113. }
  114.  
  115. /// <summary>
  116. /// 自动生成导航区域
  117. /// </summary>
  118. private void GenerateNavigationPolygon()
  119. {
  120. var tileMap = _mapRoot.GetChild(0).GetNode<TileMap>("Wall");
  121. var size = tileMap.CellSize;
  122.  
  123. var rect = tileMap.GetUsedRect();
  124.  
  125. var x = (int)rect.Position.x;
  126. var y = (int)rect.Position.y;
  127. var w = (int)rect.Size.x;
  128. var h = (int)rect.Size.y;
  129.  
  130. for (int j = y; j < h; j++)
  131. {
  132. for (int i = x; i < w; i++)
  133. {
  134. var tileId = tileMap.GetCell(i, j);
  135. if (IsWayCell(tileId))
  136. {
  137. if (!_usePoints.Contains(new Vector2(i, j)))
  138. {
  139. NavigationPolygonData polygonData = null;
  140.  
  141. if (!IsWayCell(tileMap.GetCell(i, j - 1)))
  142. {
  143. polygonData = CalcOutline(i, j, tileMap, size);
  144. }
  145. else if (!IsWayCell(tileMap.GetCell(i, j + 1)))
  146. {
  147. polygonData = CalcInline(i, j, tileMap, size);
  148. }
  149.  
  150. if (polygonData != null)
  151. {
  152. _polygonDataList.Add(polygonData);
  153. //return;
  154. }
  155. }
  156. }
  157. }
  158. }
  159. }
  160.  
  161. private NavigationPolygonData CalcOutline(int i, int j, TileMap tileMap, Vector2 size)
  162. {
  163. var polygonData = new NavigationPolygonData();
  164. var points = polygonData.Points;
  165. // 0:右, 1:下, 2:左, 3:上
  166. var dir = 0;
  167. var offset = new Vector2(size.x * 0.5f, size.y * 0.5f);
  168. //找到路, 向右开始找边界
  169. var startPos = new Vector2(i, j);
  170.  
  171. var tempI = i;
  172. var tempJ = j;
  173.  
  174. while (true)
  175. {
  176. switch (dir)
  177. {
  178. case 0: //右
  179. {
  180. if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //先向上找
  181. {
  182. dir = 3;
  183.  
  184. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  185. var pos = new Vector2(tempI, tempJ);
  186. if (points.Count > 1 && pos == startPos)
  187. {
  188. return polygonData;
  189. }
  190.  
  191. PutUsePoint(pos);
  192.  
  193. tempJ--;
  194. break;
  195. }
  196. else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //再向右找
  197. {
  198. if (points.Count == 0)
  199. {
  200. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  201. }
  202.  
  203. var pos = new Vector2(tempI, tempJ);
  204. if (points.Count > 1 && pos == startPos)
  205. {
  206. return polygonData;
  207. }
  208.  
  209. PutUsePoint(new Vector2(tempI, tempJ));
  210. tempI++;
  211. break;
  212. }
  213. else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //向下找
  214. {
  215. dir = 1;
  216.  
  217. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  218. var pos = new Vector2(tempI, tempJ);
  219. if (points.Count > 1 && pos == startPos)
  220. {
  221. return polygonData;
  222. }
  223.  
  224. PutUsePoint(pos);
  225.  
  226. tempJ++;
  227. break;
  228. }
  229.  
  230. return null;
  231. }
  232. case 1: //下
  233. {
  234. if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //先向右找
  235. {
  236. dir = 0;
  237.  
  238. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  239. var pos = new Vector2(tempI, tempJ);
  240. if (points.Count > 1 && pos == startPos)
  241. {
  242. return polygonData;
  243. }
  244.  
  245. PutUsePoint(pos);
  246.  
  247. tempI++;
  248. break;
  249. }
  250. else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //再向下找
  251. {
  252. if (points.Count == 0)
  253. {
  254. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  255. }
  256.  
  257. var pos = new Vector2(tempI, tempJ);
  258. if (points.Count > 1 && pos == startPos)
  259. {
  260. return polygonData;
  261. }
  262.  
  263. PutUsePoint(new Vector2(tempI, tempJ));
  264. tempJ++;
  265. break;
  266. }
  267. else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //向左找
  268. {
  269. dir = 2;
  270.  
  271. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  272. var pos = new Vector2(tempI, tempJ);
  273. if (points.Count > 1 && pos == startPos)
  274. {
  275. return polygonData;
  276. }
  277.  
  278. PutUsePoint(pos);
  279.  
  280. tempI--;
  281. break;
  282. }
  283.  
  284. return null;
  285. }
  286. case 2: //左
  287. {
  288. if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //先向下找
  289. {
  290. dir = 1;
  291.  
  292. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  293. var pos = new Vector2(tempI, tempJ);
  294. if (points.Count > 1 && pos == startPos)
  295. {
  296. return polygonData;
  297. }
  298.  
  299. PutUsePoint(pos);
  300.  
  301. tempJ++;
  302. break;
  303. }
  304. else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //再向左找
  305. {
  306. if (points.Count == 0)
  307. {
  308. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  309. }
  310.  
  311. var pos = new Vector2(tempI, tempJ);
  312. if (points.Count > 1 && pos == startPos)
  313. {
  314. return polygonData;
  315. }
  316.  
  317. PutUsePoint(new Vector2(tempI, tempJ));
  318. tempI--;
  319. break;
  320. }
  321. else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //向上找
  322. {
  323. dir = 3;
  324.  
  325. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  326. var pos = new Vector2(tempI, tempJ);
  327. if (points.Count > 1 && pos == startPos)
  328. {
  329. return polygonData;
  330. }
  331.  
  332. PutUsePoint(pos);
  333.  
  334. tempJ--;
  335. break;
  336. }
  337.  
  338. return null;
  339. }
  340. case 3: //上
  341. {
  342. if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //先向左找
  343. {
  344. dir = 2;
  345.  
  346. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  347. var pos = new Vector2(tempI, tempJ);
  348. if (points.Count > 1 && pos == startPos)
  349. {
  350. return polygonData;
  351. }
  352.  
  353. PutUsePoint(pos);
  354.  
  355. tempI--;
  356. break;
  357. }
  358. else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //再向上找
  359. {
  360. if (points.Count == 0)
  361. {
  362. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  363. }
  364.  
  365. var pos = new Vector2(tempI, tempJ);
  366. if (points.Count > 1 && pos == startPos)
  367. {
  368. return polygonData;
  369. }
  370.  
  371. PutUsePoint(new Vector2(tempI, tempJ));
  372. tempJ--;
  373. break;
  374. }
  375. else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //向右找
  376. {
  377. dir = 0;
  378.  
  379. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  380. var pos = new Vector2(tempI, tempJ);
  381. if (points.Count > 1 && pos == startPos)
  382. {
  383. return polygonData;
  384. }
  385.  
  386. PutUsePoint(pos);
  387.  
  388. tempI++;
  389. break;
  390. }
  391.  
  392. return null;
  393. }
  394. }
  395. }
  396. }
  397.  
  398. private NavigationPolygonData CalcInline(int i, int j, TileMap tileMap, Vector2 size)
  399. {
  400. var polygonData = new NavigationPolygonData();
  401. var points = polygonData.Points;
  402. // 0:右, 1:下, 2:左, 3:上
  403. var dir = 0;
  404. var offset = new Vector2(size.x * 0.5f, size.y * 0.5f);
  405. //找到路, 向右开始找边界
  406. var startPos = new Vector2(i, j);
  407.  
  408. var tempI = i;
  409. var tempJ = j;
  410.  
  411. while (true)
  412. {
  413. switch (dir)
  414. {
  415. case 0: //右
  416. {
  417. if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //向下找
  418. {
  419. dir = 1;
  420.  
  421. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  422. var pos = new Vector2(tempI, tempJ);
  423. if (points.Count > 1 && pos == startPos)
  424. {
  425. return polygonData;
  426. }
  427.  
  428. PutUsePoint(pos);
  429.  
  430. tempJ++;
  431. break;
  432. }
  433. else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //再向右找
  434. {
  435. if (points.Count == 0)
  436. {
  437. points.Add(new Vector2((tempI - 1) * size.x, tempJ * size.y) + offset);
  438. }
  439.  
  440. var pos = new Vector2(tempI, tempJ);
  441. if (points.Count > 1 && pos == startPos)
  442. {
  443. return polygonData;
  444. }
  445.  
  446. PutUsePoint(new Vector2(tempI, tempJ));
  447. tempI++;
  448. break;
  449. }
  450. else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //先向上找
  451. {
  452. dir = 3;
  453.  
  454. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  455. var pos = new Vector2(tempI, tempJ);
  456. if (points.Count > 1 && pos == startPos)
  457. {
  458. return polygonData;
  459. }
  460.  
  461. PutUsePoint(pos);
  462.  
  463. tempJ--;
  464. break;
  465. }
  466.  
  467. return null;
  468. }
  469. case 1: //下
  470. {
  471. if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //向左找
  472. {
  473. dir = 2;
  474.  
  475. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  476. var pos = new Vector2(tempI, tempJ);
  477. if (points.Count > 1 && pos == startPos)
  478. {
  479. return polygonData;
  480. }
  481.  
  482. PutUsePoint(pos);
  483.  
  484. tempI--;
  485. break;
  486. }
  487. else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //再向下找
  488. {
  489. if (points.Count == 0)
  490. {
  491. points.Add(new Vector2((tempI - 1) * size.x, tempJ * size.y) + offset);
  492. }
  493.  
  494. var pos = new Vector2(tempI, tempJ);
  495. if (points.Count > 1 && pos == startPos)
  496. {
  497. return polygonData;
  498. }
  499.  
  500. PutUsePoint(new Vector2(tempI, tempJ));
  501. tempJ++;
  502. break;
  503. }
  504. else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //先向右找
  505. {
  506. dir = 0;
  507.  
  508. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  509. var pos = new Vector2(tempI, tempJ);
  510. if (points.Count > 1 && pos == startPos)
  511. {
  512. return polygonData;
  513. }
  514.  
  515. PutUsePoint(pos);
  516.  
  517. tempI++;
  518. break;
  519. }
  520.  
  521. return null;
  522. }
  523. case 2: //左
  524. {
  525. if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //向上找
  526. {
  527. dir = 3;
  528.  
  529. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  530. var pos = new Vector2(tempI, tempJ);
  531. if (points.Count > 1 && pos == startPos)
  532. {
  533. return polygonData;
  534. }
  535.  
  536. PutUsePoint(pos);
  537.  
  538. tempJ--;
  539. break;
  540. }
  541. else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //再向左找
  542. {
  543. if (points.Count == 0)
  544. {
  545. points.Add(new Vector2((tempI - 1) * size.x, tempJ * size.y) + offset);
  546. }
  547.  
  548. var pos = new Vector2(tempI, tempJ);
  549. if (points.Count > 1 && pos == startPos)
  550. {
  551. return polygonData;
  552. }
  553.  
  554. PutUsePoint(new Vector2(tempI, tempJ));
  555. tempI--;
  556. break;
  557. }
  558. else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //先向下找
  559. {
  560. dir = 1;
  561.  
  562. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  563. var pos = new Vector2(tempI, tempJ);
  564. if (points.Count > 1 && pos == startPos)
  565. {
  566. return polygonData;
  567. }
  568.  
  569. PutUsePoint(pos);
  570.  
  571. tempJ++;
  572. break;
  573. }
  574.  
  575. return null;
  576. }
  577. case 3: //上
  578. {
  579. if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //向右找
  580. {
  581. dir = 0;
  582.  
  583. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  584. var pos = new Vector2(tempI, tempJ);
  585. if (points.Count > 1 && pos == startPos)
  586. {
  587. return polygonData;
  588. }
  589.  
  590. PutUsePoint(pos);
  591.  
  592. tempI++;
  593. break;
  594. }
  595. else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //再向上找
  596. {
  597. if (points.Count == 0)
  598. {
  599. points.Add(new Vector2((tempI - 1) * size.x, tempJ * size.y) + offset);
  600. }
  601.  
  602. var pos = new Vector2(tempI, tempJ);
  603. if (points.Count > 1 && pos == startPos)
  604. {
  605. return polygonData;
  606. }
  607.  
  608. PutUsePoint(new Vector2(tempI, tempJ));
  609. tempJ--;
  610. break;
  611. }
  612. else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //先向左找
  613. {
  614. dir = 2;
  615.  
  616. points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset);
  617. var pos = new Vector2(tempI, tempJ);
  618. if (points.Count > 1 && pos == startPos)
  619. {
  620. return polygonData;
  621. }
  622.  
  623. PutUsePoint(pos);
  624.  
  625. tempI--;
  626. break;
  627. }
  628.  
  629. return null;
  630. }
  631. }
  632. }
  633. }
  634.  
  635. private void PutUsePoint(Vector2 pos)
  636. {
  637. if (_usePoints.Contains(pos))
  638. {
  639. throw new Exception("生成导航多边形发生错误! 点: " + pos + "发生交错!");
  640. }
  641.  
  642. _usePoints.Add(pos);
  643. }
  644.  
  645. private bool IsWayCell(int cellId)
  646. {
  647. return cellId != -1 && _wayIds.Contains(cellId);
  648. }
  649. }