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