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