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 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 DungeonTile _dungeonTile;
  34. private AutoTileConfig _autoTileConfig;
  35. private DungeonGenerator _dungeonGenerator;
  36. //房间内所有静态导航网格数据
  37. private List<NavigationPolygonData> _roomStaticNavigationList;
  38. private World _world;
  39. //用于检查房间敌人的计时器
  40. private int _affiliationIndex = 0;
  41. private float _checkEnemyTimer = 0;
  42.  
  43.  
  44. public DungeonManager()
  45. {
  46. //绑定事件
  47. EventManager.AddEventListener(EventEnum.OnPlayerFirstEnterRoom, OnPlayerFirstEnterRoom);
  48. EventManager.AddEventListener(EventEnum.OnPlayerEnterRoom, OnPlayerEnterRoom);
  49. }
  50. /// <summary>
  51. /// 加载地牢
  52. /// </summary>
  53. public void LoadDungeon(DungeonConfig config, Action finish = null)
  54. {
  55. _config = config;
  56. GameApplication.Instance.StartCoroutine(RunLoadDungeonCoroutine(finish));
  57. }
  58.  
  59. /// <summary>
  60. /// 退出地牢
  61. /// </summary>
  62. public void ExitDungeon(Action finish = null)
  63. {
  64. IsInDungeon = false;
  65. GameApplication.Instance.StartCoroutine(RunExitDungeonCoroutine(finish));
  66. }
  67.  
  68. public override void _PhysicsProcess(double delta)
  69. {
  70. if (IsInDungeon)
  71. {
  72. _checkEnemyTimer += (float)delta;
  73. if (_checkEnemyTimer >= 1)
  74. {
  75. _checkEnemyTimer %= 1;
  76. //检查房间内的敌人存活状况
  77. OnCheckEnemy();
  78. }
  79. }
  80. }
  81.  
  82. public override void _Process(double delta)
  83. {
  84. if (IsInDungeon)
  85. {
  86. UpdateEnemiesView();
  87. if (GameApplication.Instance.Debug)
  88. {
  89. QueueRedraw();
  90. }
  91. }
  92. }
  93.  
  94. //执行加载地牢协程
  95. private IEnumerator RunLoadDungeonCoroutine(Action finish)
  96. {
  97. //打开 loading UI
  98. UiManager.Open_Loading();
  99. yield return 0;
  100. //创建世界场景
  101. _world = GameApplication.Instance.CreateNewWorld();
  102. yield return new WaitForFixedProcess(10);
  103. //生成地牢房间
  104. _dungeonGenerator = new DungeonGenerator(_config);
  105. _dungeonGenerator.Generate();
  106. yield return 0;
  107. //填充地牢
  108. _autoTileConfig = new AutoTileConfig();
  109. _dungeonTile = new DungeonTile(_world.TileRoot);
  110. _dungeonTile.AutoFillRoomTile(_autoTileConfig, _dungeonGenerator.StartRoom);
  111. yield return 0;
  112. //生成寻路网格, 这一步操作只生成过道的导航
  113. _dungeonTile.GenerateNavigationPolygon(GameConfig.AisleFloorMapLayer);
  114. yield return 0;
  115. //挂载过道导航区域
  116. _dungeonTile.MountNavigationPolygon(_world.TileRoot);
  117. yield return 0;
  118. //过道导航区域数据
  119. _roomStaticNavigationList = new List<NavigationPolygonData>();
  120. _roomStaticNavigationList.AddRange(_dungeonTile.GetPolygonData());
  121. yield return 0;
  122. //门导航区域数据
  123. _roomStaticNavigationList.AddRange(_dungeonTile.GetConnectDoorPolygonData());
  124. yield return new WaitForFixedProcess(10);
  125. //初始化所有房间
  126. _dungeonGenerator.EachRoom(InitRoom);
  127. yield return new WaitForFixedProcess(10);
  128.  
  129. //播放bgm
  130. //SoundManager.PlayMusic(ResourcePath.resource_sound_bgm_Intro_ogg, -17f);
  131.  
  132. //初始房间创建玩家标记
  133. var playerBirthMark = StartRoom.ActivityMarks.FirstOrDefault(mark => mark.Type == ActivityIdPrefix.ActivityPrefixType.Player);
  134. //创建玩家
  135. var player = ActivityObject.Create<Player>(ActivityObject.Ids.Id_role0001);
  136. if (playerBirthMark != null)
  137. {
  138. //player.Position = new Vector2(50, 50);
  139. player.Position = playerBirthMark.Position;
  140. }
  141. player.Name = "Player";
  142. player.PutDown(RoomLayerEnum.YSortLayer);
  143. Player.SetCurrentPlayer(player);
  144.  
  145. //玩家手上添加武器
  146. //player.PickUpWeapon(ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0001));
  147. // var weapon = ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0001);
  148. // weapon.PutDown(player.Position, RoomLayerEnum.NormalLayer);
  149. // var weapon2 = ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0002);
  150. // weapon2.PutDown(player.Position, RoomLayerEnum.NormalLayer);
  151. // var weapon3 = ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0003);
  152. // weapon3.PutDown(player.Position, RoomLayerEnum.NormalLayer);
  153. // var weapon4 = ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0004);
  154. // weapon4.PutDown(player.Position, RoomLayerEnum.NormalLayer);
  155.  
  156. GameApplication.Instance.Cursor.SetGuiMode(false);
  157. yield return 0;
  158. //打开游戏中的ui
  159. var roomUi = UiManager.Open_RoomUI();
  160. roomUi.InitData(player);
  161. //派发进入地牢事件
  162. EventManager.EmitEvent(EventEnum.OnEnterDungeon);
  163. IsInDungeon = true;
  164. yield return 0;
  165. //关闭 loading UI
  166. UiManager.Dispose_Loading();
  167. if (finish != null)
  168. {
  169. finish();
  170. }
  171. }
  172.  
  173. private IEnumerator RunExitDungeonCoroutine(Action finish)
  174. {
  175. //打开 loading UI
  176. UiManager.Open_Loading();
  177. yield return 0;
  178. _world.Pause = true;
  179. yield return 0;
  180. _dungeonGenerator.EachRoom(DisposeRoomInfo);
  181. yield return 0;
  182. _dungeonTile = null;
  183. _autoTileConfig = null;
  184. _dungeonGenerator = null;
  185. _roomStaticNavigationList.Clear();
  186. _roomStaticNavigationList = null;
  187. UiManager.Hide_RoomUI();
  188. yield return new WaitForFixedProcess(10);
  189. Player.SetCurrentPlayer(null);
  190. _world = null;
  191. GameApplication.Instance.DestroyWorld();
  192. yield return new WaitForFixedProcess(10);
  193. //鼠标还原
  194. GameApplication.Instance.Cursor.SetGuiMode(false);
  195. //派发退出地牢事件
  196. EventManager.EmitEvent(EventEnum.OnExitDungeon);
  197. yield return 0;
  198. //关闭 loading UI
  199. UiManager.Dispose_Loading();
  200. if (finish != null)
  201. {
  202. finish();
  203. }
  204. }
  205. // 初始化房间
  206. private void InitRoom(RoomInfo roomInfo)
  207. {
  208. //挂载房间导航区域
  209. MountNavFromRoomInfo(roomInfo);
  210. //创建门
  211. CreateDoor(roomInfo);
  212. //创建房间归属区域
  213. CreateRoomAisleAffiliation(roomInfo);
  214. }
  215. //挂载房间导航区域
  216. private void MountNavFromRoomInfo(RoomInfo roomInfo)
  217. {
  218. var polygonArray = roomInfo.RoomSplit.RoomInfo.NavigationList.ToArray();
  219. var polygon = new NavigationPolygon();
  220. var offset = roomInfo.GetOffsetPosition();
  221. for (var i = 0; i < polygonArray.Length; i++)
  222. {
  223. var navigationPolygonData = polygonArray[i];
  224. var polygonPointArray = navigationPolygonData.ConvertPointsToVector2Array();
  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. var points = new List<SerializeVector2>();
  232. for (var j = 0; j < polygonPointArray.Length; j++)
  233. {
  234. points.Add(new SerializeVector2(polygonPointArray[j]));
  235. }
  236. //存入汇总列表
  237. _roomStaticNavigationList.Add(new NavigationPolygonData(navigationPolygonData.Type, points));
  238. }
  239. polygon.MakePolygonsFromOutlines();
  240. var navigationPolygon = new NavigationRegion2D();
  241. navigationPolygon.Name = "NavigationRegion" + (GetChildCount() + 1);
  242. navigationPolygon.NavigationPolygon = polygon;
  243. _world.TileRoot.AddChild(navigationPolygon);
  244. }
  245.  
  246. //创建门
  247. private void CreateDoor(RoomInfo roomInfo)
  248. {
  249. foreach (var doorInfo in roomInfo.Doors)
  250. {
  251. RoomDoor door;
  252. switch (doorInfo.Direction)
  253. {
  254. case DoorDirection.E:
  255. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_e);
  256. door.Position = (doorInfo.OriginPosition + new Vector2(0.5f, 2)) * GameConfig.TileCellSize;
  257. door.ZIndex = GameConfig.TopMapLayer;
  258. break;
  259. case DoorDirection.W:
  260. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_w);
  261. door.Position = (doorInfo.OriginPosition + new Vector2(-0.5f, 2)) * GameConfig.TileCellSize;
  262. door.ZIndex = GameConfig.TopMapLayer;
  263. break;
  264. case DoorDirection.S:
  265. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_s);
  266. door.Position = (doorInfo.OriginPosition + new Vector2(2f, 1.5f)) * GameConfig.TileCellSize;
  267. door.ZIndex = GameConfig.TopMapLayer;
  268. break;
  269. case DoorDirection.N:
  270. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_n);
  271. door.Position = (doorInfo.OriginPosition + new Vector2(2f, -0.5f)) * GameConfig.TileCellSize;
  272. door.ZIndex = GameConfig.MiddleMapLayer;
  273. break;
  274. default:
  275. return;
  276. }
  277. doorInfo.Door = door;
  278. door.Init(doorInfo);
  279. door.PutDown(RoomLayerEnum.NormalLayer, false);
  280. }
  281. }
  282.  
  283. //创建房间归属区域
  284. private void CreateRoomAisleAffiliation(RoomInfo roomInfo)
  285. {
  286. var affiliation = new AffiliationArea();
  287. affiliation.Name = "AffiliationArea" + (_affiliationIndex++);
  288. affiliation.Init(roomInfo, new Rect2(
  289. roomInfo.GetWorldPosition() + new Vector2(GameConfig.TileCellSize, GameConfig.TileCellSize),
  290. (roomInfo.Size - new Vector2I(2, 2)) * GameConfig.TileCellSize));
  291. roomInfo.Affiliation = affiliation;
  292. _world.AddChild(affiliation);
  293. }
  294. /// <summary>
  295. /// 玩家第一次进入某个房间回调
  296. /// </summary>
  297. private void OnPlayerFirstEnterRoom(object o)
  298. {
  299. var room = (RoomInfo)o;
  300. room.BeReady();
  301. //如果关门了, 那么房间外的敌人就会丢失目标
  302. if (room.IsSeclusion)
  303. {
  304. var playerAffiliationArea = Player.Current.AffiliationArea;
  305. foreach (var enemy in _world.Enemy_InstanceList)
  306. {
  307. //不与玩家处于同一个房间
  308. if (enemy.AffiliationArea != playerAffiliationArea)
  309. {
  310. if (enemy.StateController.CurrState != AiStateEnum.AiNormal)
  311. {
  312. enemy.StateController.ChangeState(AiStateEnum.AiNormal);
  313. }
  314. }
  315. }
  316. }
  317. }
  318.  
  319. /// <summary>
  320. /// 玩家进入某个房间回调
  321. /// </summary>
  322. private void OnPlayerEnterRoom(object o)
  323. {
  324. }
  325. /// <summary>
  326. /// 检测当前房间敌人是否已经消灭干净, 应当每秒执行一次
  327. /// </summary>
  328. private void OnCheckEnemy()
  329. {
  330. var activeRoom = ActiveRoom;
  331. if (activeRoom != null)// && //activeRoom.IsSeclusion)
  332. {
  333. if (activeRoom.IsSeclusion) //房间处于关上状态
  334. {
  335. if (activeRoom.IsCurrWaveOver()) //所有标记执行完成
  336. {
  337. //是否有存活的敌人
  338. var flag = ActiveAffiliationArea.ExistIncludeItem(
  339. activityObject => activityObject.CollisionWithMask(PhysicsLayer.Enemy)
  340. );
  341. //GD.Print("当前房间存活数量: " + count);
  342. if (!flag)
  343. {
  344. activeRoom.OnClearRoom();
  345. }
  346. }
  347. }
  348. }
  349. }
  350.  
  351. /// <summary>
  352. /// 更新敌人视野
  353. /// </summary>
  354. private void UpdateEnemiesView()
  355. {
  356. _world.Enemy_IsFindTarget = false;
  357. _world.Enemy_FindTargetAffiliationSet.Clear();
  358. for (var i = 0; i < _world.Enemy_InstanceList.Count; i++)
  359. {
  360. var enemy = _world.Enemy_InstanceList[i];
  361. var state = enemy.StateController.CurrState;
  362. if (state == AiStateEnum.AiFollowUp || state == AiStateEnum.AiSurround) //目标在视野内
  363. {
  364. if (!_world.Enemy_IsFindTarget)
  365. {
  366. _world.Enemy_IsFindTarget = true;
  367. _world.Enemy_FindTargetPosition = Player.Current.GetCenterPosition();
  368. _world.Enemy_FindTargetAffiliationSet.Add(Player.Current.AffiliationArea);
  369. }
  370. _world.Enemy_FindTargetAffiliationSet.Add(enemy.AffiliationArea);
  371. }
  372. }
  373. }
  374.  
  375. private void DisposeRoomInfo(RoomInfo roomInfo)
  376. {
  377. foreach (var activityMark in roomInfo.ActivityMarks)
  378. {
  379. activityMark.QueueFree();
  380. }
  381. roomInfo.ActivityMarks.Clear();
  382. }
  383. public override void _Draw()
  384. {
  385. if (GameApplication.Instance.Debug)
  386. {
  387. if (_dungeonTile != null)
  388. {
  389. //绘制ai寻路区域
  390. Utils.DrawNavigationPolygon(this, _roomStaticNavigationList.ToArray());
  391. }
  392. //绘制房间区域
  393. // if (_dungeonGenerator != null)
  394. // {
  395. // DrawRoomInfo(StartRoom);
  396. // }
  397. //绘制边缘线
  398. }
  399. }
  400. //绘制房间区域, debug 用
  401. private void DrawRoomInfo(RoomInfo room)
  402. {
  403. var cellSize = _world.TileRoot.CellQuadrantSize;
  404. var pos1 = (room.Position + room.Size / 2) * cellSize;
  405. //绘制下一个房间
  406. foreach (var nextRoom in room.Next)
  407. {
  408. var pos2 = (nextRoom.Position + nextRoom.Size / 2) * cellSize;
  409. DrawLine(pos1, pos2, Colors.Red);
  410. DrawRoomInfo(nextRoom);
  411. }
  412.  
  413. DrawString(ResourceManager.DefaultFont16Px, pos1 - new Vector2I(0, 10), "Id: " + room.Id.ToString());
  414. DrawString(ResourceManager.DefaultFont16Px, pos1 + new Vector2I(0, 10), "Layer: " + room.Layer.ToString());
  415.  
  416. //绘制门
  417. foreach (var roomDoor in room.Doors)
  418. {
  419. var originPos = roomDoor.OriginPosition * cellSize;
  420. switch (roomDoor.Direction)
  421. {
  422. case DoorDirection.E:
  423. DrawLine(originPos, originPos + new Vector2(3, 0) * cellSize, Colors.Yellow);
  424. DrawLine(originPos + new Vector2(0, 4) * cellSize, originPos + new Vector2(3, 4) * cellSize,
  425. Colors.Yellow);
  426. break;
  427. case DoorDirection.W:
  428. DrawLine(originPos, originPos - new Vector2(3, 0) * cellSize, Colors.Yellow);
  429. DrawLine(originPos + new Vector2(0, 4) * cellSize, originPos - new Vector2(3, -4) * cellSize,
  430. Colors.Yellow);
  431. break;
  432. case DoorDirection.S:
  433. DrawLine(originPos, originPos + new Vector2(0, 3) * cellSize, Colors.Yellow);
  434. DrawLine(originPos + new Vector2(4, 0) * cellSize, originPos + new Vector2(4, 3) * cellSize,
  435. Colors.Yellow);
  436. break;
  437. case DoorDirection.N:
  438. DrawLine(originPos, originPos - new Vector2(0, 3) * cellSize, Colors.Yellow);
  439. DrawLine(originPos + new Vector2(4, 0) * cellSize, originPos - new Vector2(-4, 3) * cellSize,
  440. Colors.Yellow);
  441. break;
  442. }
  443. //绘制房间区域
  444. DrawRect(new Rect2(room.Position * cellSize, room.Size * cellSize), Colors.Blue, false);
  445.  
  446. if (roomDoor.HasCross && roomDoor.RoomInfo.Id < roomDoor.ConnectRoom.Id)
  447. {
  448. DrawRect(new Rect2(roomDoor.Cross * cellSize, new Vector2(cellSize * 4, cellSize * 4)), Colors.Yellow, false);
  449. }
  450. }
  451. }
  452. }