Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / room / DungeonManager.cs
  1.  
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using Config;
  7. using Godot;
  8.  
  9. /// <summary>
  10. /// 地牢管理器
  11. /// </summary>
  12. public partial class DungeonManager : Node2D
  13. {
  14. /// <summary>
  15. /// 起始房间
  16. /// </summary>
  17. public RoomInfo StartRoomInfo => _dungeonGenerator?.StartRoomInfo;
  18. /// <summary>
  19. /// 当前玩家所在的房间
  20. /// </summary>
  21. public RoomInfo ActiveRoomInfo => Player.Current?.AffiliationArea?.RoomInfo;
  22. /// <summary>
  23. /// 当前玩家所在的区域
  24. /// </summary>
  25. public AffiliationArea ActiveAffiliationArea => Player.Current?.AffiliationArea;
  26.  
  27. /// <summary>
  28. /// 是否在地牢里
  29. /// </summary>
  30. public bool IsInDungeon { get; private set; }
  31.  
  32. private DungeonConfig _config;
  33. private DungeonTileMap _dungeonTileMap;
  34. private AutoTileConfig _autoTileConfig;
  35. private DungeonGenerator _dungeonGenerator;
  36. //房间内所有静态导航网格数据
  37. private List<NavigationPolygonData> _roomStaticNavigationList;
  38. private World _world;
  39. //用于检查房间敌人的计时器
  40. private float _checkEnemyTimer = 0;
  41.  
  42.  
  43. public DungeonManager()
  44. {
  45. //绑定事件
  46. EventManager.AddEventListener(EventEnum.OnPlayerFirstEnterRoom, OnPlayerFirstEnterRoom);
  47. EventManager.AddEventListener(EventEnum.OnPlayerEnterRoom, OnPlayerEnterRoom);
  48. }
  49. /// <summary>
  50. /// 加载地牢
  51. /// </summary>
  52. public void LoadDungeon(DungeonConfig config, Action finish = null)
  53. {
  54. _config = config;
  55. GameApplication.Instance.StartCoroutine(RunLoadDungeonCoroutine(finish));
  56. }
  57.  
  58. /// <summary>
  59. /// 退出地牢
  60. /// </summary>
  61. public void ExitDungeon(Action finish = null)
  62. {
  63. IsInDungeon = false;
  64. GameApplication.Instance.StartCoroutine(RunExitDungeonCoroutine(finish));
  65. }
  66.  
  67. public override void _Process(double delta)
  68. {
  69. if (IsInDungeon)
  70. {
  71. _checkEnemyTimer += (float)delta;
  72. if (_checkEnemyTimer >= 1)
  73. {
  74. _checkEnemyTimer %= 1;
  75. //检查房间内的敌人存活状况
  76. OnCheckEnemy();
  77. }
  78. //更新敌人视野
  79. UpdateEnemiesView();
  80. if (GameApplication.Instance.Debug)
  81. {
  82. QueueRedraw();
  83. }
  84. }
  85. }
  86.  
  87. //执行加载地牢协程
  88. private IEnumerator RunLoadDungeonCoroutine(Action finish)
  89. {
  90. //打开 loading UI
  91. UiManager.Open_Loading();
  92. yield return 0;
  93. //创建世界场景
  94. _world = GameApplication.Instance.CreateNewWorld();
  95. yield return new WaitForFixedProcess(10);
  96. //生成地牢房间
  97. _dungeonGenerator = new DungeonGenerator(_config);
  98. _dungeonGenerator.Generate();
  99. yield return 0;
  100. //填充地牢
  101. _autoTileConfig = new AutoTileConfig();
  102. _dungeonTileMap = new DungeonTileMap(_world.TileRoot);
  103. _dungeonTileMap.AutoFillRoomTile(_autoTileConfig, _dungeonGenerator.StartRoomInfo, _dungeonGenerator.Random);
  104. yield return 0;
  105. //生成寻路网格, 这一步操作只生成过道的导航
  106. _dungeonTileMap.GenerateNavigationPolygon(GameConfig.AisleFloorMapLayer);
  107. yield return 0;
  108. //挂载过道导航区域
  109. _dungeonTileMap.MountNavigationPolygon(_world.TileRoot);
  110. yield return 0;
  111. //过道导航区域数据
  112. _roomStaticNavigationList = new List<NavigationPolygonData>();
  113. _roomStaticNavigationList.AddRange(_dungeonTileMap.GetPolygonData());
  114. yield return 0;
  115. //门导航区域数据
  116. _roomStaticNavigationList.AddRange(_dungeonTileMap.GetConnectDoorPolygonData());
  117. yield return new WaitForFixedProcess(10);
  118. //初始化所有房间
  119. _dungeonGenerator.EachRoom(InitRoom);
  120. yield return new WaitForFixedProcess(10);
  121.  
  122. //播放bgm
  123. //SoundManager.PlayMusic(ResourcePath.resource_sound_bgm_Intro_ogg, -17f);
  124.  
  125. //初始房间创建玩家标记
  126. var playerBirthMark = StartRoomInfo.RoomPreinstall.GetPlayerBirthMark();
  127. //创建玩家
  128. var player = ActivityObject.Create<Player>(ActivityObject.Ids.Id_role0001);
  129. if (playerBirthMark != null)
  130. {
  131. //player.Position = new Vector2(50, 50);
  132. player.Position = playerBirthMark.Position;
  133. }
  134. player.Name = "Player";
  135. player.PutDown(RoomLayerEnum.YSortLayer);
  136. Player.SetCurrentPlayer(player);
  137. //地牢加载即将完成
  138. _dungeonGenerator.EachRoom(info => info.OnReady());
  139.  
  140. //玩家手上添加武器
  141. //player.PickUpWeapon(ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0001));
  142. // var weapon = ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0001);
  143. // weapon.PutDown(player.Position, RoomLayerEnum.NormalLayer);
  144. // var weapon2 = ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0002);
  145. // weapon2.PutDown(player.Position, RoomLayerEnum.NormalLayer);
  146. // var weapon3 = ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0003);
  147. // weapon3.PutDown(player.Position, RoomLayerEnum.NormalLayer);
  148. // var weapon4 = ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0004);
  149. // weapon4.PutDown(player.Position, RoomLayerEnum.NormalLayer);
  150.  
  151. GameApplication.Instance.Cursor.SetGuiMode(false);
  152. yield return 0;
  153. //打开游戏中的ui
  154. UiManager.Open_RoomUI();
  155. //派发进入地牢事件
  156. EventManager.EmitEvent(EventEnum.OnEnterDungeon);
  157. IsInDungeon = true;
  158. QueueRedraw();
  159. yield return 0;
  160. //关闭 loading UI
  161. UiManager.Destroy_Loading();
  162. if (finish != null)
  163. {
  164. finish();
  165. }
  166. }
  167.  
  168. private IEnumerator RunExitDungeonCoroutine(Action finish)
  169. {
  170. //打开 loading UI
  171. UiManager.Open_Loading();
  172. yield return 0;
  173. _world.Pause = true;
  174. yield return 0;
  175. _dungeonGenerator.EachRoom(DisposeRoomInfo);
  176. yield return 0;
  177. _dungeonTileMap = null;
  178. _autoTileConfig = null;
  179. _dungeonGenerator = null;
  180. _roomStaticNavigationList.Clear();
  181. _roomStaticNavigationList = null;
  182. UiManager.Hide_RoomUI();
  183. yield return new WaitForFixedProcess(10);
  184. Player.SetCurrentPlayer(null);
  185. _world = null;
  186. GameApplication.Instance.DestroyWorld();
  187. yield return new WaitForFixedProcess(10);
  188. QueueRedraw();
  189. //鼠标还原
  190. GameApplication.Instance.Cursor.SetGuiMode(true);
  191. //派发退出地牢事件
  192. EventManager.EmitEvent(EventEnum.OnExitDungeon);
  193. yield return 0;
  194. //关闭 loading UI
  195. UiManager.Destroy_Loading();
  196. if (finish != null)
  197. {
  198. finish();
  199. }
  200. }
  201. // 初始化房间
  202. private void InitRoom(RoomInfo roomInfo)
  203. {
  204. //挂载房间导航区域
  205. MountNavFromRoomInfo(roomInfo);
  206. //创建门
  207. CreateDoor(roomInfo);
  208. //创建房间归属区域
  209. CreateRoomAffiliation(roomInfo);
  210. //创建静态精灵画布
  211. CreateRoomStaticSpriteCanvas(roomInfo);
  212. }
  213. //挂载房间导航区域
  214. private void MountNavFromRoomInfo(RoomInfo roomInfo)
  215. {
  216. var polygonArray = roomInfo.RoomSplit.TileInfo.NavigationList;
  217. var polygon = new NavigationPolygon();
  218. var offset = roomInfo.GetOffsetPosition();
  219. for (var i = 0; i < polygonArray.Count; i++)
  220. {
  221. var navigationPolygonData = polygonArray[i];
  222. var tempPosArray = navigationPolygonData.GetPoints();
  223. var polygonPointArray = new Vector2[tempPosArray.Length];
  224. //这里的位置需要加上房间位置
  225. for (var j = 0; j < tempPosArray.Length; j++)
  226. {
  227. polygonPointArray[j] = tempPosArray[j] + roomInfo.GetWorldPosition() - offset;
  228. }
  229. polygon.AddOutline(polygonPointArray);
  230.  
  231. //存入汇总列表
  232. var polygonData = new NavigationPolygonData(navigationPolygonData.Type);
  233. polygonData.SetPoints(polygonPointArray);
  234. _roomStaticNavigationList.Add(polygonData);
  235. }
  236. polygon.MakePolygonsFromOutlines();
  237. var navigationPolygon = new NavigationRegion2D();
  238. navigationPolygon.Name = "NavigationRegion" + (GetChildCount() + 1);
  239. navigationPolygon.NavigationPolygon = polygon;
  240. _world.TileRoot.AddChild(navigationPolygon);
  241. }
  242.  
  243. //创建门
  244. private void CreateDoor(RoomInfo roomInfo)
  245. {
  246. foreach (var doorInfo in roomInfo.Doors)
  247. {
  248. RoomDoor door;
  249. switch (doorInfo.Direction)
  250. {
  251. case DoorDirection.E:
  252. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_e);
  253. door.Position = (doorInfo.OriginPosition + new Vector2(0.5f, 2)) * GameConfig.TileCellSize;
  254. door.ZIndex = GameConfig.TopMapLayer;
  255. break;
  256. case DoorDirection.W:
  257. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_w);
  258. door.Position = (doorInfo.OriginPosition + new Vector2(-0.5f, 2)) * GameConfig.TileCellSize;
  259. door.ZIndex = GameConfig.TopMapLayer;
  260. break;
  261. case DoorDirection.S:
  262. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_s);
  263. door.Position = (doorInfo.OriginPosition + new Vector2(2f, 1.5f)) * GameConfig.TileCellSize;
  264. door.ZIndex = GameConfig.TopMapLayer;
  265. break;
  266. case DoorDirection.N:
  267. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_n);
  268. door.Position = (doorInfo.OriginPosition + new Vector2(2f, -0.5f)) * GameConfig.TileCellSize;
  269. door.ZIndex = GameConfig.MiddleMapLayer;
  270. break;
  271. default:
  272. return;
  273. }
  274. doorInfo.Door = door;
  275. door.Init(doorInfo);
  276. door.PutDown(RoomLayerEnum.NormalLayer, false);
  277. }
  278. }
  279.  
  280. //创建房间归属区域
  281. private void CreateRoomAffiliation(RoomInfo roomInfo)
  282. {
  283. var affiliation = new AffiliationArea();
  284. affiliation.Name = "AffiliationArea" + roomInfo.Id;
  285. affiliation.Init(roomInfo, new Rect2(
  286. roomInfo.GetWorldPosition() + new Vector2(GameConfig.TileCellSize, GameConfig.TileCellSize),
  287. (roomInfo.Size - new Vector2I(2, 2)) * GameConfig.TileCellSize));
  288. roomInfo.AffiliationArea = affiliation;
  289. _world.AffiliationAreaRoot.AddChild(affiliation);
  290. }
  291.  
  292. //创建静态精灵画布
  293. private void CreateRoomStaticSpriteCanvas(RoomInfo roomInfo)
  294. {
  295. var worldPos = roomInfo.GetWorldPosition();
  296. var pos = new Vector2I((int)worldPos.X, (int)worldPos.Y);
  297. int minX = pos.X;
  298. int minY = pos.Y;
  299. int maxX = minX + roomInfo.GetWidth();
  300. int maxY = minY + roomInfo.GetHeight();
  301.  
  302. //遍历每一个连接的门, 计算计算canvas覆盖范围
  303. foreach (var doorInfo in roomInfo.Doors)
  304. {
  305. var connectDoor = doorInfo.ConnectDoor;
  306. switch (connectDoor.Direction)
  307. {
  308. case DoorDirection.E:
  309. case DoorDirection.W:
  310. {
  311. var (px1, py1) = connectDoor.GetWorldOriginPosition();
  312. var py2 = py1 + 4 * GameConfig.TileCellSize;
  313. if (px1 < minX)
  314. {
  315. minX = px1;
  316. }
  317. else if (px1 > maxX)
  318. {
  319. maxX = px1;
  320. }
  321.  
  322. if (py1 < minY)
  323. {
  324. minY = py1;
  325. }
  326. else if (py1 > maxY)
  327. {
  328. maxY = py1;
  329. }
  330. if (py2 < minY)
  331. {
  332. minY = py2;
  333. }
  334. else if (py2 > maxY)
  335. {
  336. maxY = py2;
  337. }
  338. }
  339. break;
  340. case DoorDirection.S:
  341. case DoorDirection.N:
  342. {
  343. var (px1, py1) = connectDoor.GetWorldOriginPosition();
  344. var px2 = px1 + 4 * GameConfig.TileCellSize;
  345. if (px1 < minX)
  346. {
  347. minX = px1;
  348. }
  349. else if (px1 > maxX)
  350. {
  351. maxX = px1;
  352. }
  353.  
  354. if (py1 < minY)
  355. {
  356. minY = py1;
  357. }
  358. else if (py1 > maxY)
  359. {
  360. maxY = py1;
  361. }
  362. if (px2 < minX)
  363. {
  364. minX = px2;
  365. }
  366. else if (px2 > maxX)
  367. {
  368. maxX = px2;
  369. }
  370. }
  371. break;
  372. }
  373. }
  374.  
  375. minX -= GameConfig.TileCellSize;
  376. minY -= GameConfig.TileCellSize;
  377. maxX += GameConfig.TileCellSize;
  378. maxY += GameConfig.TileCellSize;
  379. var staticSpriteCanvas = new RoomStaticImageCanvas(
  380. _world.StaticSpriteRoot,
  381. new Vector2I(minX, minY),
  382. maxX - minX, maxY - minY
  383. );
  384. staticSpriteCanvas.RoomOffset = new Vector2I(worldPos.X - minX, worldPos.Y - minY);
  385. roomInfo.StaticImageCanvas = staticSpriteCanvas;
  386. }
  387.  
  388. /// <summary>
  389. /// 玩家第一次进入某个房间回调
  390. /// </summary>
  391. private void OnPlayerFirstEnterRoom(object o)
  392. {
  393. var room = (RoomInfo)o;
  394. room.OnFirstEnter();
  395. //如果关门了, 那么房间外的敌人就会丢失目标
  396. if (room.IsSeclusion)
  397. {
  398. var playerAffiliationArea = Player.Current.AffiliationArea;
  399. foreach (var enemy in _world.Enemy_InstanceList)
  400. {
  401. //不与玩家处于同一个房间
  402. if (enemy.AffiliationArea != playerAffiliationArea)
  403. {
  404. if (enemy.StateController.CurrState != AiStateEnum.AiNormal)
  405. {
  406. enemy.StateController.ChangeState(AiStateEnum.AiNormal);
  407. }
  408. }
  409. }
  410. }
  411. }
  412.  
  413. /// <summary>
  414. /// 玩家进入某个房间回调
  415. /// </summary>
  416. private void OnPlayerEnterRoom(object o)
  417. {
  418. }
  419. /// <summary>
  420. /// 检测当前房间敌人是否已经消灭干净, 应当每秒执行一次
  421. /// </summary>
  422. private void OnCheckEnemy()
  423. {
  424. var activeRoom = ActiveRoomInfo;
  425. if (activeRoom != null)// && //activeRoom.IsSeclusion)
  426. {
  427. if (activeRoom.IsSeclusion) //房间处于关上状态
  428. {
  429. if (activeRoom.IsCurrWaveOver()) //所有标记执行完成
  430. {
  431. //是否有存活的敌人
  432. var flag = ActiveAffiliationArea.ExistIncludeItem(
  433. activityObject => activityObject.CollisionWithMask(PhysicsLayer.Enemy)
  434. );
  435. //GD.Print("当前房间存活数量: " + count);
  436. if (!flag)
  437. {
  438. activeRoom.OnClearRoom();
  439. }
  440. }
  441. }
  442. }
  443. }
  444.  
  445. /// <summary>
  446. /// 更新敌人视野
  447. /// </summary>
  448. private void UpdateEnemiesView()
  449. {
  450. _world.Enemy_IsFindTarget = false;
  451. _world.Enemy_FindTargetAffiliationSet.Clear();
  452. for (var i = 0; i < _world.Enemy_InstanceList.Count; i++)
  453. {
  454. var enemy = _world.Enemy_InstanceList[i];
  455. var state = enemy.StateController.CurrState;
  456. if (state == AiStateEnum.AiFollowUp || state == AiStateEnum.AiSurround) //目标在视野内
  457. {
  458. if (!_world.Enemy_IsFindTarget)
  459. {
  460. _world.Enemy_IsFindTarget = true;
  461. _world.Enemy_FindTargetPosition = Player.Current.GetCenterPosition();
  462. _world.Enemy_FindTargetAffiliationSet.Add(Player.Current.AffiliationArea);
  463. }
  464. _world.Enemy_FindTargetAffiliationSet.Add(enemy.AffiliationArea);
  465. }
  466. }
  467. }
  468.  
  469. private void DisposeRoomInfo(RoomInfo roomInfo)
  470. {
  471. roomInfo.Destroy();
  472. }
  473. public override void _Draw()
  474. {
  475. if (GameApplication.Instance.Debug)
  476. {
  477. if (_dungeonTileMap != null)
  478. {
  479. //绘制ai寻路区域
  480. Utils.DrawNavigationPolygon(this, _roomStaticNavigationList.ToArray());
  481. }
  482. //绘制房间区域
  483. // if (_dungeonGenerator != null)
  484. // {
  485. // DrawRoomInfo(StartRoom);
  486. // }
  487. //绘制边缘线
  488. }
  489. }
  490. //绘制房间区域, debug 用
  491. private void DrawRoomInfo(RoomInfo roomInfo)
  492. {
  493. var cellSize = _world.TileRoot.CellQuadrantSize;
  494. var pos1 = (roomInfo.Position + roomInfo.Size / 2) * cellSize;
  495. //绘制下一个房间
  496. foreach (var nextRoom in roomInfo.Next)
  497. {
  498. var pos2 = (nextRoom.Position + nextRoom.Size / 2) * cellSize;
  499. DrawLine(pos1, pos2, Colors.Red);
  500. DrawRoomInfo(nextRoom);
  501. }
  502.  
  503. DrawString(ResourceManager.DefaultFont16Px, pos1 - new Vector2I(0, 10), "Id: " + roomInfo.Id.ToString());
  504. DrawString(ResourceManager.DefaultFont16Px, pos1 + new Vector2I(0, 10), "Layer: " + roomInfo.Layer.ToString());
  505.  
  506. //绘制门
  507. foreach (var roomDoor in roomInfo.Doors)
  508. {
  509. var originPos = roomDoor.OriginPosition * cellSize;
  510. switch (roomDoor.Direction)
  511. {
  512. case DoorDirection.E:
  513. DrawLine(originPos, originPos + new Vector2(3, 0) * cellSize, Colors.Yellow);
  514. DrawLine(originPos + new Vector2(0, 4) * cellSize, originPos + new Vector2(3, 4) * cellSize,
  515. Colors.Yellow);
  516. break;
  517. case DoorDirection.W:
  518. DrawLine(originPos, originPos - new Vector2(3, 0) * cellSize, Colors.Yellow);
  519. DrawLine(originPos + new Vector2(0, 4) * cellSize, originPos - new Vector2(3, -4) * cellSize,
  520. Colors.Yellow);
  521. break;
  522. case DoorDirection.S:
  523. DrawLine(originPos, originPos + new Vector2(0, 3) * cellSize, Colors.Yellow);
  524. DrawLine(originPos + new Vector2(4, 0) * cellSize, originPos + new Vector2(4, 3) * cellSize,
  525. Colors.Yellow);
  526. break;
  527. case DoorDirection.N:
  528. DrawLine(originPos, originPos - new Vector2(0, 3) * cellSize, Colors.Yellow);
  529. DrawLine(originPos + new Vector2(4, 0) * cellSize, originPos - new Vector2(-4, 3) * cellSize,
  530. Colors.Yellow);
  531. break;
  532. }
  533. //绘制房间区域
  534. DrawRect(new Rect2(roomInfo.Position * cellSize, roomInfo.Size * cellSize), Colors.Blue, false);
  535.  
  536. if (roomDoor.HasCross && roomDoor.RoomInfo.Id < roomDoor.ConnectRoom.Id)
  537. {
  538. DrawRect(new Rect2(roomDoor.Cross * cellSize, new Vector2(cellSize * 4, cellSize * 4)), Colors.Yellow, false);
  539. }
  540. }
  541. }
  542. /// <summary>
  543. /// 将房间类型枚举转为字符串
  544. /// </summary>
  545. public static string DungeonRoomTypeToString(DungeonRoomType roomType)
  546. {
  547. switch (roomType)
  548. {
  549. case DungeonRoomType.Battle: return "battle";
  550. case DungeonRoomType.Inlet: return "inlet";
  551. case DungeonRoomType.Outlet: return "outlet";
  552. case DungeonRoomType.Boss: return "boss";
  553. case DungeonRoomType.Reward: return "reward";
  554. case DungeonRoomType.Shop: return "shop";
  555. case DungeonRoomType.Event: return "event";
  556. }
  557.  
  558. return "battle";
  559. }
  560. /// <summary>
  561. /// 将房间类型枚举转为描述字符串
  562. /// </summary>
  563. public static string DungeonRoomTypeToDescribeString(DungeonRoomType roomType)
  564. {
  565. switch (roomType)
  566. {
  567. case DungeonRoomType.Battle: return "战斗房间";
  568. case DungeonRoomType.Inlet: return "起始房间";
  569. case DungeonRoomType.Outlet: return "结束房间";
  570. case DungeonRoomType.Boss: return "Boss房间";
  571. case DungeonRoomType.Reward: return "奖励房间";
  572. case DungeonRoomType.Shop: return "商店房间";
  573. case DungeonRoomType.Event: return "事件房间";
  574. }
  575.  
  576. return "战斗房间";
  577. }
  578. }