Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / room / DungeonManager.cs
@小李xl 小李xl on 5 Apr 2024 36 KB World中Enemy_List改为Role_List
  1.  
  2. using System;
  3. using System.Collections;
  4. using Godot;
  5.  
  6. /// <summary>
  7. /// 地牢管理器
  8. /// </summary>
  9. public partial class DungeonManager : Node2D
  10. {
  11. /// <summary>
  12. /// 起始房间
  13. /// </summary>
  14. public RoomInfo StartRoomInfo => _dungeonGenerator?.StartRoomInfo;
  15. /// <summary>
  16. /// 当前玩家所在的房间
  17. /// </summary>
  18. public RoomInfo ActiveRoomInfo => CurrWorld.Player?.AffiliationArea?.RoomInfo;
  19. /// <summary>
  20. /// 当前玩家所在的区域
  21. /// </summary>
  22. public AffiliationArea ActiveAffiliationArea => CurrWorld.Player?.AffiliationArea;
  23.  
  24. /// <summary>
  25. /// 是否在地牢里
  26. /// </summary>
  27. public bool IsInDungeon { get; private set; }
  28.  
  29. /// <summary>
  30. /// 是否是编辑器模式
  31. /// </summary>
  32. public bool IsEditorMode { get; private set; }
  33. /// <summary>
  34. /// 当前使用的配置
  35. /// </summary>
  36. public DungeonConfig CurrConfig { get; private set; }
  37. /// <summary>
  38. /// 当前玩家所在游戏世界对象
  39. /// </summary>
  40. public World CurrWorld { get; private set; }
  41.  
  42. /// <summary>
  43. /// 自动图块配置
  44. /// </summary>
  45. public AutoTileConfig AutoTileConfig { get; private set; }
  46.  
  47. private UiBase _prevUi;
  48. private DungeonTileMap _dungeonTileMap;
  49. private DungeonGenerator _dungeonGenerator;
  50. //用于检查房间敌人的计时器
  51. private float _checkEnemyTimer = 0;
  52. //用于记录玩家上一个所在区域
  53. private AffiliationArea _affiliationAreaFlag;
  54.  
  55.  
  56. public DungeonManager()
  57. {
  58. //绑定事件
  59. EventManager.AddEventListener(EventEnum.OnPlayerFirstEnterRoom, OnPlayerFirstEnterRoom);
  60. EventManager.AddEventListener(EventEnum.OnPlayerEnterRoom, OnPlayerEnterRoom);
  61. }
  62. /// <summary>
  63. /// 创建新的 World 对象, 相当于清理房间
  64. /// </summary>
  65. public World CreateNewWorld(SeedRandom random, string scenePath)
  66. {
  67. if (CurrWorld != null)
  68. {
  69. ClearWorld();
  70. CurrWorld.QueueFree();
  71. }
  72. CurrWorld = ResourceManager.LoadAndInstantiate<World>(scenePath);
  73. GameApplication.Instance.SceneRoot.AddChild(CurrWorld);
  74. CurrWorld.InitRandomPool(random);
  75. return CurrWorld;
  76. }
  77.  
  78. /// <summary>
  79. /// 销毁 World 对象, 相当于清理房间
  80. /// </summary>
  81. public void DestroyWorld()
  82. {
  83. //销毁所有物体
  84. if (CurrWorld != null)
  85. {
  86. ClearWorld();
  87. CurrWorld.QueueFree();
  88. }
  89. //销毁池中所有物体
  90. ObjectPool.DisposeAllItem();
  91.  
  92. CurrWorld = null;
  93. }
  94. //清理世界
  95. private void ClearWorld()
  96. {
  97. var childCount = CurrWorld.NormalLayer.GetChildCount();
  98. for (var i = 0; i < childCount; i++)
  99. {
  100. var c = CurrWorld.NormalLayer.GetChild(i);
  101. if (c is IDestroy destroy)
  102. {
  103. destroy.Destroy();
  104. }
  105. }
  106. childCount = CurrWorld.YSortLayer.GetChildCount();
  107. for (var i = 0; i < childCount; i++)
  108. {
  109. var c = CurrWorld.YSortLayer.GetChild(i);
  110. if (c is IDestroy destroy)
  111. {
  112. destroy.Destroy();
  113. }
  114. }
  115. }
  116.  
  117. /// <summary>
  118. /// 进入大厅
  119. /// </summary>
  120. public void LoadHall(Action finish = null)
  121. {
  122. GameApplication.Instance.StartCoroutine(RunLoadHallCoroutine(finish));
  123. }
  124.  
  125. /// <summary>
  126. /// 退出大厅
  127. /// </summary>
  128. public void ExitHall(bool keepPlayer, Action finish = null)
  129. {
  130. GameApplication.Instance.StartCoroutine(RunExitHallCoroutine(keepPlayer, finish));
  131. }
  132. /// <summary>
  133. /// 加载地牢
  134. /// </summary>
  135. public void LoadDungeon(DungeonConfig config, Action finish = null)
  136. {
  137. IsEditorMode = false;
  138. CurrConfig = config;
  139. GameApplication.Instance.StartCoroutine(RunLoadDungeonCoroutine(finish));
  140. }
  141. /// <summary>
  142. /// 重启地牢
  143. /// </summary>
  144. public void RestartDungeon(bool keepPlayer, DungeonConfig config, Action finish = null)
  145. {
  146. IsEditorMode = false;
  147. CurrConfig = config;
  148. ExitDungeon(keepPlayer, () =>
  149. {
  150. LoadDungeon(CurrConfig, finish);
  151. });
  152. }
  153.  
  154. /// <summary>
  155. /// 退出地牢
  156. /// </summary>
  157. public void ExitDungeon(bool keepPlayer, Action finish = null)
  158. {
  159. IsInDungeon = false;
  160. GameApplication.Instance.StartCoroutine(RunExitDungeonCoroutine(keepPlayer, finish));
  161. }
  162. //-------------------------------------------------------------------------------------
  163.  
  164. /// <summary>
  165. /// 在编辑器模式下进入地牢
  166. /// </summary>
  167. /// <param name="config">地牢配置</param>
  168. /// <param name="finish">执行完成回调</param>
  169. public void EditorPlayDungeon(DungeonConfig config, Action finish = null)
  170. {
  171. IsEditorMode = true;
  172. CurrConfig = config;
  173. if (_prevUi != null)
  174. {
  175. _prevUi.HideUi();
  176. }
  177. GameApplication.Instance.StartCoroutine(RunLoadDungeonCoroutine(finish));
  178. }
  179.  
  180. /// <summary>
  181. /// 在编辑器模式下进入地牢
  182. /// </summary>
  183. /// <param name="prevUi">记录上一个Ui</param>
  184. /// <param name="config">地牢配置</param>
  185. /// <param name="finish">执行完成回调</param>
  186. public void EditorPlayDungeon(UiBase prevUi, DungeonConfig config, Action finish = null)
  187. {
  188. IsEditorMode = true;
  189. CurrConfig = config;
  190. _prevUi = prevUi;
  191. if (_prevUi != null)
  192. {
  193. _prevUi.HideUi();
  194. }
  195. GameApplication.Instance.StartCoroutine(RunLoadDungeonCoroutine(finish));
  196. }
  197.  
  198. /// <summary>
  199. /// 在编辑器模式下退出地牢, 并且打开上一个Ui
  200. /// </summary>
  201. public void EditorExitDungeon(bool keepPlayer, Action finish = null)
  202. {
  203. IsInDungeon = false;
  204. GameApplication.Instance.StartCoroutine(RunExitDungeonCoroutine(keepPlayer, () =>
  205. {
  206. IsEditorMode = false;
  207. //显示上一个Ui
  208. if (_prevUi != null)
  209. {
  210. _prevUi.ShowUi();
  211. }
  212. if (finish != null)
  213. {
  214. finish();
  215. }
  216. }));
  217. }
  218. //-------------------------------------------------------------------------------------
  219.  
  220. public override void _Process(double delta)
  221. {
  222. if (IsInDungeon)
  223. {
  224. if (CurrWorld.Pause) //已经暂停
  225. {
  226. return;
  227. }
  228. //暂停游戏
  229. if (InputManager.Menu)
  230. {
  231. CurrWorld.Pause = true;
  232. //鼠标改为Ui鼠标
  233. GameApplication.Instance.Cursor.SetGuiMode(true);
  234. //打开暂停Ui
  235. UiManager.Open_PauseMenu();
  236. }
  237. //更新迷雾
  238. FogMaskHandler.Update();
  239. _checkEnemyTimer += (float)delta;
  240. if (_checkEnemyTimer >= 1)
  241. {
  242. _checkEnemyTimer %= 1;
  243. //检查房间内的敌人存活状况
  244. OnCheckEnemy();
  245. }
  246. if (ActivityObject.IsDebug)
  247. {
  248. QueueRedraw();
  249. }
  250. }
  251. }
  252.  
  253. //执行加载大厅流程
  254. private IEnumerator RunLoadHallCoroutine(Action finish)
  255. {
  256. yield return 0;
  257. var hall = (Hall)CreateNewWorld(Utils.Random, ResourcePath.scene_Hall_tscn);
  258. yield return 0;
  259.  
  260. //创建房间数据
  261. var roomInfo = new RoomInfo(0, DungeonRoomType.None, null);
  262. roomInfo.World = CurrWorld;
  263. roomInfo.Size = hall.BgSprite.Texture.GetSize().AsVector2I() / GameConfig.TileCellSize + new Vector2I(10, 10);
  264. roomInfo.Position = hall.BgSprite.Position.AsVector2I() - new Vector2I(5, 5) * GameConfig.TileCellSize;
  265. hall.RoomInfo = roomInfo;
  266. yield return 0;
  267. //创建归属区域
  268. var affiliation = new AffiliationArea();
  269. affiliation.Name = "AffiliationArea_Hall";
  270. affiliation.Init(roomInfo, new Rect2I(roomInfo.Position, roomInfo.Size * GameConfig.TileCellSize));
  271. roomInfo.AffiliationArea = affiliation;
  272. hall.AffiliationAreaRoot.AddChild(affiliation);
  273. yield return 0;
  274. //静态渲染精灵根节点, 用于放置sprite
  275. var spriteRoot = new RoomStaticSprite(roomInfo);
  276. spriteRoot.Name = "SpriteRoot";
  277. roomInfo.StaticSprite = spriteRoot;
  278. hall.StaticSpriteRoot.AddChild(spriteRoot);
  279. yield return 0;
  280. //静态精灵画布
  281. var canvasSprite = new ImageCanvas(roomInfo.Size.X * GameConfig.TileCellSize, roomInfo.Size.Y * GameConfig.TileCellSize);
  282. canvasSprite.Position = roomInfo.Position;
  283. roomInfo.StaticImageCanvas = canvasSprite;
  284. roomInfo.StaticSprite.AddChild(canvasSprite);
  285. yield return 0;
  286. //液体画布
  287. var liquidCanvas = new LiquidCanvas(roomInfo, roomInfo.Size.X * GameConfig.TileCellSize, roomInfo.Size.Y * GameConfig.TileCellSize);
  288. liquidCanvas.Position = roomInfo.Position;
  289. roomInfo.LiquidCanvas = liquidCanvas;
  290. roomInfo.StaticSprite.AddChild(liquidCanvas);
  291. yield return 0;
  292. //打开游戏中的ui
  293. UiManager.Open_RoomUI();
  294. yield return 0;
  295. //创建玩家
  296. var player = CurrWorld.Player;
  297. if (player == null)
  298. {
  299. player = ActivityObject.Create<Player>(ActivityObject.Ids.Id_role0001);
  300. player.Name = "Player";
  301. }
  302. player.World = CurrWorld;
  303. player.Position = hall.BirthMark.Position;
  304. player.PutDown(RoomLayerEnum.YSortLayer);
  305. CurrWorld.SetCurrentPlayer(player);
  306. affiliation.InsertItem(player);
  307. player.WeaponPack.PickupItem(ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0001));
  308. yield return 0;
  309. player.Collision.Disabled = false;
  310. GameApplication.Instance.Cursor.SetGuiMode(false);
  311. yield return 0;
  312. IsInDungeon = true;
  313.  
  314. if (finish != null)
  315. {
  316. finish();
  317. }
  318. }
  319. //执行退出大厅流程
  320. private IEnumerator RunExitHallCoroutine(bool keepPlayer, Action finish)
  321. {
  322. IsInDungeon = false;
  323. yield return 0;
  324. CurrWorld.Pause = true;
  325. yield return 0;
  326.  
  327. var hall = (Hall)CurrWorld;
  328. hall.RoomInfo.Destroy();
  329. yield return 0;
  330. UiManager.Destroy_RoomUI();
  331. yield return 0;
  332. if (!keepPlayer)
  333. {
  334. CurrWorld.SetCurrentPlayer(null);
  335. }
  336. else
  337. {
  338. var player = CurrWorld.Player;
  339. player.AffiliationArea?.RemoveItem(player);
  340. player.GetParent().RemoveChild(player);
  341. player.World = null;
  342. player.Collision.Disabled = true;
  343. }
  344.  
  345. DestroyWorld();
  346. yield return 0;
  347. FogMaskHandler.ClearRecordRoom();
  348. LiquidBrushManager.ClearData();
  349. BrushImageData.ClearBrushData();
  350. QueueRedraw();
  351. //鼠标还原
  352. GameApplication.Instance.Cursor.SetGuiMode(true);
  353. yield return 0;
  354. if (finish != null)
  355. {
  356. finish();
  357. }
  358. }
  359.  
  360. //执行加载地牢协程
  361. private IEnumerator RunLoadDungeonCoroutine(Action finish)
  362. {
  363. yield return 0;
  364. //生成地牢房间
  365. //最多尝试10次
  366. const int maxCount = 10;
  367. for (var i = 0; i < maxCount; i++)
  368. {
  369. SeedRandom random;
  370. if (CurrConfig.RandomSeed != null)
  371. {
  372. random = new SeedRandom(CurrConfig.RandomSeed.Value);
  373. }
  374. else
  375. {
  376. random = new SeedRandom();
  377. }
  378. var dungeonGenerator = new DungeonGenerator(CurrConfig, random);
  379. var rule = new DefaultDungeonRule(dungeonGenerator);
  380. if (!dungeonGenerator.Generate(rule)) //生成房间失败
  381. {
  382. dungeonGenerator.EachRoom(DisposeRoomInfo);
  383. if (i == maxCount - 1)
  384. {
  385. if (IsEditorMode) //在编辑器模式下打开的Ui
  386. {
  387. EditorPlayManager.IsPlay = false;
  388. IsEditorMode = false;
  389. //显示上一个Ui
  390. if (_prevUi != null)
  391. {
  392. _prevUi.ShowUi();
  393. //尝试关闭加载Ui
  394. UiManager.Destroy_Loading();
  395. }
  396. }
  397. else //正常关闭Ui
  398. {
  399. UiManager.Open_Main();
  400. //尝试关闭加载Ui
  401. UiManager.Destroy_Loading();
  402. }
  403. EditorWindowManager.ShowTips("错误", "生成房间尝试次数过多,生成地牢房间失败,请加大房间门连接区域,或者修改地牢生成规则!");
  404. yield break;
  405. }
  406. else
  407. {
  408. yield return 0;
  409. }
  410. }
  411. else //生成成功!
  412. {
  413. _dungeonGenerator = dungeonGenerator;
  414. break;
  415. }
  416. }
  417. yield return 0;
  418. //创建世界场景
  419. var dungeon = (Dungeon)CreateNewWorld(_dungeonGenerator.Random, ResourcePath.scene_Dungeon_tscn);
  420. dungeon.InitLayer();
  421. //初始化房间 World 字段
  422. foreach (var roomInfo in _dungeonGenerator.RoomInfos)
  423. {
  424. roomInfo.World = dungeon;
  425. }
  426. yield return 0;
  427. var group = GameApplication.Instance.RoomConfig[CurrConfig.GroupName];
  428. var tileSetSplit = GameApplication.Instance.TileSetConfig[group.TileSet];
  429. CurrWorld.TileRoot.TileSet = tileSetSplit.GetTileSet();
  430. //填充地牢
  431. AutoTileConfig = new AutoTileConfig(0, tileSetSplit.TileSetInfo.Sources[0].Terrain[0]);
  432. _dungeonTileMap = new DungeonTileMap(CurrWorld.TileRoot);
  433. yield return _dungeonTileMap.AutoFillRoomTile(AutoTileConfig, _dungeonGenerator.StartRoomInfo, CurrWorld);
  434. yield return _dungeonTileMap.AutoFillAisleTile(AutoTileConfig, _dungeonGenerator.StartRoomInfo, CurrWorld);
  435. //yield return _dungeonTileMap.AddOutlineTile(AutoTileConfig.WALL_BLOCK);
  436. yield return 0;
  437. //生成墙壁, 生成导航网格
  438. _dungeonTileMap.GenerateWallAndNavigation(CurrWorld, AutoTileConfig);
  439. yield return 0;
  440. //初始化所有房间
  441. yield return _dungeonGenerator.EachRoomCoroutine(InitRoom);
  442.  
  443. //播放bgm
  444. //SoundManager.PlayMusic(ResourcePath.resource_sound_bgm_Intro_ogg, -17f);
  445.  
  446. //地牢加载即将完成
  447. yield return _dungeonGenerator.EachRoomCoroutine(info => info.OnReady());
  448. //打开游戏中的ui
  449. UiManager.Open_RoomUI();
  450. yield return 0;
  451. //初始房间创建玩家标记
  452. var playerBirthMark = StartRoomInfo.RoomPreinstall.GetSpecialMark(SpecialMarkType.BirthPoint);
  453. //创建玩家
  454. var player = CurrWorld.Player;
  455. if (player == null)
  456. {
  457. player = ActivityObject.Create<Player>(ActivityObject.Ids.Id_role0001);
  458. player.Name = "Player";
  459. }
  460. if (playerBirthMark != null)
  461. {
  462. player.Position = playerBirthMark.Position;
  463. }
  464.  
  465. player.World = CurrWorld;
  466. player.PutDown(RoomLayerEnum.YSortLayer);
  467. CurrWorld.SetCurrentPlayer(player);
  468. StartRoomInfo.AffiliationArea.InsertItem(player);
  469. yield return 0;
  470. player.Collision.Disabled = false;
  471. GameApplication.Instance.Cursor.SetGuiMode(false);
  472. //派发进入地牢事件
  473. EventManager.EmitEvent(EventEnum.OnEnterDungeon);
  474. IsInDungeon = true;
  475. QueueRedraw();
  476. yield return 0;
  477. if (finish != null)
  478. {
  479. finish();
  480. }
  481. }
  482.  
  483. //执行退出地牢流程
  484. private IEnumerator RunExitDungeonCoroutine(bool keepPlayer, Action finish)
  485. {
  486. yield return 0;
  487. CurrWorld.Pause = true;
  488. yield return 0;
  489. _dungeonGenerator?.EachRoom(DisposeRoomInfo);
  490. yield return 0;
  491. _dungeonTileMap = null;
  492. AutoTileConfig = null;
  493. _dungeonGenerator = null;
  494. UiManager.Destroy_RoomUI();
  495. yield return 0;
  496. if (!keepPlayer)
  497. {
  498. CurrWorld.SetCurrentPlayer(null);
  499. }
  500. else
  501. {
  502. var player = CurrWorld.Player;
  503. player.AffiliationArea?.RemoveItem(player);
  504. player.GetParent().RemoveChild(player);
  505. player.World = null;
  506. player.Collision.Disabled = true;
  507. }
  508.  
  509. DestroyWorld();
  510. yield return 0;
  511. FogMaskHandler.ClearRecordRoom();
  512. LiquidBrushManager.ClearData();
  513. BrushImageData.ClearBrushData();
  514. QueueRedraw();
  515. //鼠标还原
  516. GameApplication.Instance.Cursor.SetGuiMode(true);
  517. //派发退出地牢事件
  518. EventManager.EmitEvent(EventEnum.OnExitDungeon);
  519. yield return 0;
  520. if (finish != null)
  521. {
  522. finish();
  523. }
  524. }
  525.  
  526. // 初始化房间
  527. private void InitRoom(RoomInfo roomInfo)
  528. {
  529. roomInfo.CalcRange();
  530. //创建门
  531. CreateDoor(roomInfo);
  532. //创建房间归属区域
  533. CreateRoomAffiliation(roomInfo);
  534. //创建 RoomStaticSprite
  535. CreateRoomStaticSprite(roomInfo);
  536. //创建静态精灵画布
  537. CreateRoomStaticImageCanvas(roomInfo);
  538. //创建液体区域
  539. CreateRoomLiquidCanvas(roomInfo);
  540. //创建迷雾遮罩
  541. CreateRoomFogMask(roomInfo);
  542. //创建房间/过道预览sprite
  543. CreatePreviewSprite(roomInfo);
  544. }
  545.  
  546. //创建门
  547. private void CreateDoor(RoomInfo roomInfo)
  548. {
  549. foreach (var doorInfo in roomInfo.Doors)
  550. {
  551. RoomDoor door;
  552. switch (doorInfo.Direction)
  553. {
  554. case DoorDirection.E:
  555. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_e);
  556. door.Position = (doorInfo.OriginPosition + new Vector2(0.5f, 2)) * GameConfig.TileCellSize;
  557. break;
  558. case DoorDirection.W:
  559. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_w);
  560. door.Position = (doorInfo.OriginPosition + new Vector2(-0.5f, 2)) * GameConfig.TileCellSize;
  561. break;
  562. case DoorDirection.S:
  563. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_s);
  564. door.Position = (doorInfo.OriginPosition + new Vector2(2f, 1.5f)) * GameConfig.TileCellSize;
  565. break;
  566. case DoorDirection.N:
  567. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_n);
  568. door.Position = (doorInfo.OriginPosition + new Vector2(2f, -0.5f)) * GameConfig.TileCellSize;
  569. break;
  570. default:
  571. return;
  572. }
  573. doorInfo.Door = door;
  574. door.Init(doorInfo);
  575. door.PutDown(RoomLayerEnum.YSortLayer, false);
  576. }
  577. }
  578.  
  579. //创建房间归属区域
  580. private void CreateRoomAffiliation(RoomInfo roomInfo)
  581. {
  582. var affiliation = new AffiliationArea();
  583. affiliation.Name = "AffiliationArea" + roomInfo.Id;
  584. affiliation.Init(roomInfo, new Rect2I(
  585. roomInfo.GetWorldPosition() + new Vector2I(GameConfig.TileCellSize * 2, GameConfig.TileCellSize * 3),
  586. (roomInfo.Size - new Vector2I(4, 5)) * GameConfig.TileCellSize));
  587. roomInfo.AffiliationArea = affiliation;
  588. CurrWorld.AffiliationAreaRoot.AddChild(affiliation);
  589. }
  590.  
  591. //创建 RoomStaticSprite
  592. private void CreateRoomStaticSprite(RoomInfo roomInfo)
  593. {
  594. var spriteRoot = new RoomStaticSprite(roomInfo);
  595. spriteRoot.Name = "SpriteRoot";
  596. World.Current.StaticSpriteRoot.AddChild(spriteRoot);
  597. roomInfo.StaticSprite = spriteRoot;
  598. }
  599. //创建液体画布
  600. private void CreateRoomLiquidCanvas(RoomInfo roomInfo)
  601. {
  602. var rect = roomInfo.CanvasRect;
  603.  
  604. var liquidCanvas = new LiquidCanvas(roomInfo, rect.Size.X, rect.Size.Y);
  605. liquidCanvas.Position = rect.Position;
  606. roomInfo.LiquidCanvas = liquidCanvas;
  607. roomInfo.StaticSprite.AddChild(liquidCanvas);
  608. }
  609.  
  610. //创建静态图像画布
  611. private void CreateRoomStaticImageCanvas(RoomInfo roomInfo)
  612. {
  613. var rect = roomInfo.CanvasRect;
  614.  
  615. var canvasSprite = new ImageCanvas(rect.Size.X, rect.Size.Y);
  616. canvasSprite.Position = rect.Position;
  617. roomInfo.StaticImageCanvas = canvasSprite;
  618. roomInfo.StaticSprite.AddChild(canvasSprite);
  619. }
  620.  
  621. //创建迷雾遮罩
  622. private void CreateRoomFogMask(RoomInfo roomInfo)
  623. {
  624. var roomFog = new FogMask();
  625. roomFog.Name = "FogMask" + roomFog.IsDestroyed;
  626. roomFog.InitFog(roomInfo.Position + new Vector2I(1, 0), roomInfo.Size - new Vector2I(2, 1));
  627. //roomFog.InitFog(roomInfo.Position + new Vector2I(1, 1), roomInfo.Size - new Vector2I(2, 2));
  628.  
  629. CurrWorld.FogMaskRoot.AddChild(roomFog);
  630. roomInfo.RoomFogMask = roomFog;
  631. //生成通道迷雾
  632. foreach (var roomDoorInfo in roomInfo.Doors)
  633. {
  634. //必须是正向门
  635. if (roomDoorInfo.IsForward)
  636. {
  637. Rect2I calcRect;
  638. Rect2I fogAreaRect;
  639. if (!roomDoorInfo.HasCross)
  640. {
  641. calcRect = roomDoorInfo.GetAisleRect();
  642. fogAreaRect = calcRect;
  643. if (roomDoorInfo.Direction == DoorDirection.E || roomDoorInfo.Direction == DoorDirection.W)
  644. {
  645. calcRect.Position += new Vector2I(2, 0);
  646. calcRect.Size -= new Vector2I(4, 0);
  647. }
  648. else
  649. {
  650. calcRect.Position += new Vector2I(0, 2);
  651. calcRect.Size -= new Vector2I(0, 5);
  652. }
  653. }
  654. else
  655. {
  656. var aisleRect = roomDoorInfo.GetCrossAisleRect();
  657. calcRect = aisleRect.CalcAisleRect();
  658. fogAreaRect = calcRect;
  659.  
  660. if (roomDoorInfo.Direction == DoorDirection.E)
  661. {
  662. if (roomDoorInfo.ConnectDoor.Direction == DoorDirection.N) //→↑
  663. {
  664. calcRect.Position += new Vector2I(2, 0);
  665. calcRect.Size -= new Vector2I(2, 4);
  666. }
  667. else //→↓
  668. {
  669. calcRect.Position += new Vector2I(2, 3);
  670. calcRect.Size -= new Vector2I(2, 3);
  671. }
  672. }
  673. else if (roomDoorInfo.Direction == DoorDirection.W)
  674. {
  675. if (roomDoorInfo.ConnectDoor.Direction == DoorDirection.N) //←↑
  676. {
  677. calcRect.Size -= new Vector2I(2, 4);
  678. }
  679. else //←↓
  680. {
  681. calcRect.Position += new Vector2I(0, 3);
  682. calcRect.Size -= new Vector2I(2, 3);
  683. }
  684. }
  685. else if (roomDoorInfo.Direction == DoorDirection.N)
  686. {
  687. if (roomDoorInfo.ConnectDoor.Direction == DoorDirection.E) //↑→
  688. {
  689. calcRect.Position += new Vector2I(2, -1);
  690. calcRect.Size -= new Vector2I(2, 2);
  691. }
  692. else //↑←
  693. {
  694. calcRect.Position += new Vector2I(0, -1);
  695. calcRect.Size -= new Vector2I(2, 2);
  696. }
  697. }
  698. else if (roomDoorInfo.Direction == DoorDirection.S)
  699. {
  700. if (roomDoorInfo.ConnectDoor.Direction == DoorDirection.E) //↓→
  701. {
  702. calcRect.Position += new Vector2I(2, 2);
  703. calcRect.Size -= new Vector2I(2, 1);
  704. }
  705. else //↓←
  706. {
  707. calcRect.Position += new Vector2I(0, 2);
  708. calcRect.Size -= new Vector2I(2, 1);
  709. }
  710. }
  711. }
  712.  
  713. //过道迷雾遮罩
  714. var aisleFog = new FogMask();
  715. var calcRectSize = calcRect.Size;
  716. var calcRectPosition = calcRect.Position;
  717. if (roomDoorInfo.Direction == DoorDirection.N || roomDoorInfo.Direction == DoorDirection.S)
  718. {
  719. calcRectSize.Y -= 1;
  720. }
  721. else
  722. {
  723. calcRectPosition.Y -= 1;
  724. calcRectSize.Y += 1;
  725. }
  726.  
  727. aisleFog.InitFog(calcRectPosition, calcRectSize);
  728. CurrWorld.FogMaskRoot.AddChild(aisleFog);
  729. roomDoorInfo.AisleFogMask = aisleFog;
  730. roomDoorInfo.ConnectDoor.AisleFogMask = aisleFog;
  731.  
  732. //过道迷雾区域
  733. var fogArea = new AisleFogArea();
  734. fogArea.Init(roomDoorInfo,
  735. new Rect2I(
  736. fogAreaRect.Position * GameConfig.TileCellSize,
  737. fogAreaRect.Size * GameConfig.TileCellSize
  738. )
  739. );
  740. roomDoorInfo.AisleFogArea = fogArea;
  741. roomDoorInfo.ConnectDoor.AisleFogArea = fogArea;
  742. CurrWorld.AffiliationAreaRoot.AddChild(fogArea);
  743. }
  744.  
  745. //预览迷雾区域
  746. var previewRoomFog = new PreviewFogMask();
  747. roomDoorInfo.PreviewRoomFogMask = previewRoomFog;
  748. previewRoomFog.Init(roomDoorInfo, PreviewFogMask.PreviewFogType.Room);
  749. previewRoomFog.SetActive(false);
  750. CurrWorld.FogMaskRoot.AddChild(previewRoomFog);
  751. var previewAisleFog = new PreviewFogMask();
  752. roomDoorInfo.PreviewAisleFogMask = previewAisleFog;
  753. previewAisleFog.Init(roomDoorInfo, PreviewFogMask.PreviewFogType.Aisle);
  754. previewAisleFog.SetActive(false);
  755. CurrWorld.FogMaskRoot.AddChild(previewAisleFog);
  756. }
  757. }
  758.  
  759. private void CreatePreviewSprite(RoomInfo roomInfo)
  760. {
  761. //房间区域
  762. var sprite = new TextureRect();
  763. //sprite.Centered = false;
  764. sprite.Texture = roomInfo.PreviewTexture;
  765. sprite.Position = roomInfo.Position + new Vector2I(1, 3);
  766. var material = ResourceManager.Load<ShaderMaterial>(ResourcePath.resource_material_Outline2_tres, false);
  767. material.SetShaderParameter("outline_color", new Color(1, 1, 1, 0.9f));
  768. material.SetShaderParameter("scale", 0.5f);
  769. sprite.Material = material;
  770. roomInfo.PreviewSprite = sprite;
  771. //过道
  772. if (roomInfo.Doors != null)
  773. {
  774. foreach (var doorInfo in roomInfo.Doors)
  775. {
  776. if (doorInfo.IsForward)
  777. {
  778. var aisleSprite = new TextureRect();
  779. //aisleSprite.Centered = false;
  780. aisleSprite.Texture = doorInfo.AislePreviewTexture;
  781. //调整过道预览位置
  782. if (doorInfo.Direction == DoorDirection.N || doorInfo.Direction == DoorDirection.S ||
  783. doorInfo.ConnectDoor.Direction == DoorDirection.N || doorInfo.ConnectDoor.Direction == DoorDirection.S)
  784. {
  785. aisleSprite.Position = doorInfo.AisleFloorRect.Position + new Vector2I(0, 1);
  786. }
  787. else
  788. {
  789. aisleSprite.Position = doorInfo.AisleFloorRect.Position;
  790. }
  791.  
  792. // var aisleSpriteMaterial = ResourceManager.Load<ShaderMaterial>(ResourcePath.resource_material_Outline2_tres, false);
  793. // aisleSpriteMaterial.SetShaderParameter("outline_color", new Color(1, 1, 1, 0.9f));
  794. // aisleSpriteMaterial.SetShaderParameter("scale", 0.5f);
  795. // aisleSprite.Material = aisleSpriteMaterial;
  796. doorInfo.AislePreviewSprite = aisleSprite;
  797. doorInfo.ConnectDoor.AislePreviewSprite = aisleSprite;
  798. }
  799. }
  800. }
  801. }
  802. /// <summary>
  803. /// 玩家第一次进入某个房间回调
  804. /// </summary>
  805. private void OnPlayerFirstEnterRoom(object o)
  806. {
  807. var room = (RoomInfo)o;
  808. room.OnFirstEnter();
  809. //如果关门了, 那么房间外的敌人就会丢失目标
  810. if (room.IsSeclusion)
  811. {
  812. var playerAffiliationArea = CurrWorld.Player.AffiliationArea;
  813. foreach (var role in CurrWorld.Role_InstanceList)
  814. {
  815. //不与玩家处于同一个房间
  816. if (role is AiRole enemy && !enemy.IsDestroyed && enemy.AffiliationArea != playerAffiliationArea)
  817. {
  818. if (enemy.StateController.CurrState != AIStateEnum.AiNormal)
  819. {
  820. enemy.StateController.ChangeState(AIStateEnum.AiNormal);
  821. }
  822. }
  823. }
  824. }
  825. }
  826.  
  827. /// <summary>
  828. /// 玩家进入某个房间回调
  829. /// </summary>
  830. private void OnPlayerEnterRoom(object o)
  831. {
  832. var roomInfo = (RoomInfo)o;
  833. if (_affiliationAreaFlag != roomInfo.AffiliationArea)
  834. {
  835. if (!roomInfo.AffiliationArea.IsDestroyed)
  836. {
  837. //刷新迷雾
  838. FogMaskHandler.RefreshRoomFog(roomInfo);
  839. }
  840.  
  841. _affiliationAreaFlag = roomInfo.AffiliationArea;
  842. }
  843. }
  844. /// <summary>
  845. /// 检测当前房间敌人是否已经消灭干净, 应当每秒执行一次
  846. /// </summary>
  847. private void OnCheckEnemy()
  848. {
  849. var activeRoom = ActiveRoomInfo;
  850. if (activeRoom != null && activeRoom.RoomPreinstall != null)
  851. {
  852. if (activeRoom.RoomPreinstall.IsRunWave) //正在生成标记
  853. {
  854. if (activeRoom.RoomPreinstall.IsCurrWaveOver()) //所有标记执行完成
  855. {
  856. //房间内是否有存活的敌人
  857. var flag = ActiveAffiliationArea.ExistEnterItem(
  858. activityObject => activityObject is Role role && role.IsEnemyWithPlayer()
  859. );
  860. //Debug.Log("当前房间存活数量: " + count);
  861. if (!flag)
  862. {
  863. activeRoom.OnClearRoom();
  864. }
  865. }
  866. }
  867. }
  868. }
  869.  
  870. private void DisposeRoomInfo(RoomInfo roomInfo)
  871. {
  872. roomInfo.Destroy();
  873. }
  874. public override void _Draw()
  875. {
  876. if (ActivityObject.IsDebug)
  877. {
  878. StartRoomInfo?.EachRoom(info =>
  879. {
  880. DrawRect(new Rect2(info.Waypoints * GameConfig.TileCellSize, new Vector2(16, 16)), Colors.Red);
  881. });
  882. //绘制房间区域
  883. if (_dungeonGenerator != null)
  884. {
  885. DrawRoomInfo(StartRoomInfo);
  886. }
  887. //绘制边缘线
  888.  
  889. }
  890. }
  891. //绘制房间区域, debug 用
  892. private void DrawRoomInfo(RoomInfo roomInfo)
  893. {
  894. var cellSize = GameConfig.TileCellSize;
  895. var pos1 = (roomInfo.Position + roomInfo.Size / 2) * cellSize;
  896. //绘制下一个房间
  897. foreach (var nextRoom in roomInfo.Next)
  898. {
  899. var pos2 = (nextRoom.Position + nextRoom.Size / 2) * cellSize;
  900. DrawLine(pos1, pos2, Colors.Red);
  901. DrawRoomInfo(nextRoom);
  902. }
  903.  
  904. DrawString(ResourceManager.DefaultFont16Px, pos1 - new Vector2I(0, 10), "Id: " + roomInfo.Id.ToString());
  905. DrawString(ResourceManager.DefaultFont16Px, pos1 + new Vector2I(0, 10), "Layer: " + roomInfo.Layer.ToString());
  906.  
  907. //绘制门
  908. foreach (var roomDoor in roomInfo.Doors)
  909. {
  910. var originPos = roomDoor.OriginPosition * cellSize;
  911. switch (roomDoor.Direction)
  912. {
  913. case DoorDirection.E:
  914. DrawLine(originPos, originPos + new Vector2(3, 0) * cellSize, Colors.Yellow);
  915. DrawLine(originPos + new Vector2(0, 4) * cellSize, originPos + new Vector2(3, 4) * cellSize,
  916. Colors.Yellow);
  917. break;
  918. case DoorDirection.W:
  919. DrawLine(originPos, originPos - new Vector2(3, 0) * cellSize, Colors.Yellow);
  920. DrawLine(originPos + new Vector2(0, 4) * cellSize, originPos - new Vector2(3, -4) * cellSize,
  921. Colors.Yellow);
  922. break;
  923. case DoorDirection.S:
  924. DrawLine(originPos, originPos + new Vector2(0, 3) * cellSize, Colors.Yellow);
  925. DrawLine(originPos + new Vector2(4, 0) * cellSize, originPos + new Vector2(4, 3) * cellSize,
  926. Colors.Yellow);
  927. break;
  928. case DoorDirection.N:
  929. DrawLine(originPos, originPos - new Vector2(0, 3) * cellSize, Colors.Yellow);
  930. DrawLine(originPos + new Vector2(4, 0) * cellSize, originPos - new Vector2(-4, 3) * cellSize,
  931. Colors.Yellow);
  932. break;
  933. }
  934. //绘制房间区域
  935. DrawRect(new Rect2(roomInfo.Position * cellSize, roomInfo.Size * cellSize), Colors.Blue, false);
  936.  
  937. if (roomDoor.HasCross && roomDoor.RoomInfo.Id < roomDoor.ConnectRoom.Id)
  938. {
  939. DrawRect(new Rect2(roomDoor.Cross * cellSize, new Vector2(cellSize * 4, cellSize * 4)), Colors.Yellow, false);
  940. }
  941. }
  942. }
  943. /// <summary>
  944. /// 将房间类型枚举转为字符串
  945. /// </summary>
  946. public static string DungeonRoomTypeToString(DungeonRoomType roomType)
  947. {
  948. switch (roomType)
  949. {
  950. case DungeonRoomType.Battle: return "battle";
  951. case DungeonRoomType.Inlet: return "inlet";
  952. case DungeonRoomType.Outlet: return "outlet";
  953. case DungeonRoomType.Boss: return "boss";
  954. case DungeonRoomType.Reward: return "reward";
  955. case DungeonRoomType.Shop: return "shop";
  956. case DungeonRoomType.Event: return "event";
  957. }
  958.  
  959. return "battle";
  960. }
  961. /// <summary>
  962. /// 将房间类型枚举转为描述字符串
  963. /// </summary>
  964. public static string DungeonRoomTypeToDescribeString(DungeonRoomType roomType)
  965. {
  966. switch (roomType)
  967. {
  968. case DungeonRoomType.Battle: return "战斗房间";
  969. case DungeonRoomType.Inlet: return "起始房间";
  970. case DungeonRoomType.Outlet: return "结束房间";
  971. case DungeonRoomType.Boss: return "Boss房间";
  972. case DungeonRoomType.Reward: return "奖励房间";
  973. case DungeonRoomType.Shop: return "商店房间";
  974. case DungeonRoomType.Event: return "事件房间";
  975. }
  976.  
  977. return "战斗房间";
  978. }
  979.  
  980. /// <summary>
  981. /// 检测地牢是否可以执行生成
  982. /// </summary>
  983. /// <param name="groupName">组名称</param>
  984. public static DungeonCheckState CheckDungeon(string groupName)
  985. {
  986. if (GameApplication.Instance.RoomConfig.TryGetValue(groupName, out var group))
  987. {
  988. //验证该组是否满足生成地牢的条件
  989. if (group.InletList.Count == 0)
  990. {
  991. return new DungeonCheckState(true, "当没有可用的起始房间!");
  992. }
  993. else if (group.OutletList.Count == 0)
  994. {
  995. return new DungeonCheckState(true, "没有可用的结束房间!");
  996. }
  997. else if (group.BattleList.Count == 0)
  998. {
  999. return new DungeonCheckState(true, "没有可用的战斗房间!");
  1000. }
  1001.  
  1002. return new DungeonCheckState(false, null);
  1003. }
  1004.  
  1005. return new DungeonCheckState(true, "未找到地牢组");
  1006. }
  1007. }