Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / room / DungeonManager.cs
  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 => Player.Current?.AffiliationArea?.RoomInfo;
  19. /// <summary>
  20. /// 当前玩家所在的区域
  21. /// </summary>
  22. public AffiliationArea ActiveAffiliationArea => Player.Current?.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.Size = hall.BgSprite.Texture.GetSize().AsVector2I() / GameConfig.TileCellSize + new Vector2I(10, 10);
  263. roomInfo.Position = hall.BgSprite.Position.AsVector2I() - new Vector2I(5, 5) * GameConfig.TileCellSize;
  264. hall.RoomInfo = roomInfo;
  265. yield return 0;
  266. //创建归属区域
  267. var affiliation = new AffiliationArea();
  268. affiliation.Name = "AffiliationArea_Hall";
  269. affiliation.Init(roomInfo, new Rect2I(roomInfo.Position, roomInfo.Size * GameConfig.TileCellSize));
  270. roomInfo.AffiliationArea = affiliation;
  271. hall.AffiliationAreaRoot.AddChild(affiliation);
  272. yield return 0;
  273. //静态渲染精灵根节点, 用于放置sprite
  274. var spriteRoot = new RoomStaticSprite(roomInfo);
  275. spriteRoot.Name = "SpriteRoot";
  276. roomInfo.StaticSprite = spriteRoot;
  277. hall.StaticSpriteRoot.AddChild(spriteRoot);
  278. yield return 0;
  279. //静态精灵画布
  280. var canvasSprite = new ImageCanvas(roomInfo.Size.X * GameConfig.TileCellSize, roomInfo.Size.Y * GameConfig.TileCellSize);
  281. canvasSprite.Position = roomInfo.Position;
  282. roomInfo.StaticImageCanvas = canvasSprite;
  283. roomInfo.StaticSprite.AddChild(canvasSprite);
  284. yield return 0;
  285. //液体画布
  286. var liquidCanvas = new LiquidCanvas(roomInfo, roomInfo.Size.X * GameConfig.TileCellSize, roomInfo.Size.Y * GameConfig.TileCellSize);
  287. liquidCanvas.Position = roomInfo.Position;
  288. roomInfo.LiquidCanvas = liquidCanvas;
  289. roomInfo.StaticSprite.AddChild(liquidCanvas);
  290. yield return 0;
  291. //打开游戏中的ui
  292. UiManager.Open_RoomUI();
  293. yield return 0;
  294. //创建玩家
  295. var player = Player.Current;
  296. if (player == null)
  297. {
  298. player = ActivityObject.Create<Player>(ActivityObject.Ids.Id_role0001);
  299. player.Name = "Player";
  300. }
  301. player.World = CurrWorld;
  302. player.Position = hall.BirthMark.Position;
  303. player.PutDown(RoomLayerEnum.YSortLayer);
  304. Player.SetCurrentPlayer(player);
  305. affiliation.InsertItem(player);
  306. player.WeaponPack.PickupItem(ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0001));
  307. yield return 0;
  308. player.Collision.Disabled = false;
  309. GameApplication.Instance.Cursor.SetGuiMode(false);
  310. yield return 0;
  311. IsInDungeon = true;
  312.  
  313. if (finish != null)
  314. {
  315. finish();
  316. }
  317. }
  318. //执行退出大厅流程
  319. private IEnumerator RunExitHallCoroutine(bool keepPlayer, Action finish)
  320. {
  321. IsInDungeon = false;
  322. yield return 0;
  323. CurrWorld.Pause = true;
  324. yield return 0;
  325.  
  326. var hall = (Hall)CurrWorld;
  327. hall.RoomInfo.Destroy();
  328. yield return 0;
  329. UiManager.Destroy_RoomUI();
  330. yield return 0;
  331. if (!keepPlayer)
  332. {
  333. Player.SetCurrentPlayer(null);
  334. }
  335. else
  336. {
  337. var player = Player.Current;
  338. player.AffiliationArea?.RemoveItem(player);
  339. player.GetParent().RemoveChild(player);
  340. player.World = null;
  341. player.Collision.Disabled = true;
  342. }
  343.  
  344. DestroyWorld();
  345. yield return 0;
  346. FogMaskHandler.ClearRecordRoom();
  347. LiquidBrushManager.ClearData();
  348. BrushImageData.ClearBrushData();
  349. QueueRedraw();
  350. //鼠标还原
  351. GameApplication.Instance.Cursor.SetGuiMode(true);
  352. yield return 0;
  353. if (finish != null)
  354. {
  355. finish();
  356. }
  357. }
  358.  
  359. //执行加载地牢协程
  360. private IEnumerator RunLoadDungeonCoroutine(Action finish)
  361. {
  362. yield return 0;
  363. //生成地牢房间
  364. //最多尝试10次
  365. const int maxCount = 10;
  366. for (var i = 0; i < maxCount; i++)
  367. {
  368. SeedRandom random;
  369. if (CurrConfig.RandomSeed != null)
  370. {
  371. random = new SeedRandom(CurrConfig.RandomSeed.Value);
  372. }
  373. else
  374. {
  375. random = new SeedRandom();
  376. }
  377. var dungeonGenerator = new DungeonGenerator(CurrConfig, random);
  378. var rule = new DefaultDungeonRule(dungeonGenerator);
  379. if (!dungeonGenerator.Generate(rule)) //生成房间失败
  380. {
  381. dungeonGenerator.EachRoom(DisposeRoomInfo);
  382. if (i == maxCount - 1)
  383. {
  384. if (IsEditorMode) //在编辑器模式下打开的Ui
  385. {
  386. EditorPlayManager.IsPlay = false;
  387. IsEditorMode = false;
  388. //显示上一个Ui
  389. if (_prevUi != null)
  390. {
  391. _prevUi.ShowUi();
  392. //尝试关闭加载Ui
  393. UiManager.Destroy_Loading();
  394. }
  395. }
  396. else //正常关闭Ui
  397. {
  398. UiManager.Open_Main();
  399. //尝试关闭加载Ui
  400. UiManager.Destroy_Loading();
  401. }
  402. EditorWindowManager.ShowTips("错误", "生成房间尝试次数过多,生成地牢房间失败,请加大房间门连接区域,或者修改地牢生成规则!");
  403. yield break;
  404. }
  405. else
  406. {
  407. yield return 0;
  408. }
  409. }
  410. else //生成成功!
  411. {
  412. _dungeonGenerator = dungeonGenerator;
  413. break;
  414. }
  415. }
  416. yield return 0;
  417. //创建世界场景
  418. var dungeon = (Dungeon)CreateNewWorld(_dungeonGenerator.Random, ResourcePath.scene_Dungeon_tscn);
  419. dungeon.InitLayer();
  420. yield return 0;
  421. var group = GameApplication.Instance.RoomConfig[CurrConfig.GroupName];
  422. var tileSetSplit = GameApplication.Instance.TileSetConfig[group.TileSet];
  423. CurrWorld.TileRoot.TileSet = tileSetSplit.GetTileSet();
  424. //填充地牢
  425. AutoTileConfig = new AutoTileConfig(0, tileSetSplit.TileSetInfo.Sources[0].Terrain[0]);
  426. _dungeonTileMap = new DungeonTileMap(CurrWorld.TileRoot);
  427. yield return _dungeonTileMap.AutoFillRoomTile(AutoTileConfig, _dungeonGenerator.StartRoomInfo, CurrWorld);
  428. yield return _dungeonTileMap.AutoFillAisleTile(AutoTileConfig, _dungeonGenerator.StartRoomInfo, CurrWorld);
  429. //yield return _dungeonTileMap.AddOutlineTile(AutoTileConfig.WALL_BLOCK);
  430. yield return 0;
  431. //生成墙壁, 生成导航网格
  432. _dungeonTileMap.GenerateWallAndNavigation(CurrWorld, AutoTileConfig);
  433. yield return 0;
  434. //初始化所有房间
  435. yield return _dungeonGenerator.EachRoomCoroutine(InitRoom);
  436.  
  437. //播放bgm
  438. //SoundManager.PlayMusic(ResourcePath.resource_sound_bgm_Intro_ogg, -17f);
  439.  
  440. //地牢加载即将完成
  441. yield return _dungeonGenerator.EachRoomCoroutine(info => info.OnReady());
  442. //打开游戏中的ui
  443. UiManager.Open_RoomUI();
  444. yield return 0;
  445. //初始房间创建玩家标记
  446. var playerBirthMark = StartRoomInfo.RoomPreinstall.GetPlayerBirthMark();
  447. //创建玩家
  448. var player = Player.Current;
  449. if (player == null)
  450. {
  451. player = ActivityObject.Create<Player>(ActivityObject.Ids.Id_role0001);
  452. player.Name = "Player";
  453. }
  454. if (playerBirthMark != null)
  455. {
  456. player.Position = playerBirthMark.Position;
  457. }
  458.  
  459. player.World = CurrWorld;
  460. player.PutDown(RoomLayerEnum.YSortLayer);
  461. Player.SetCurrentPlayer(player);
  462. StartRoomInfo.AffiliationArea.InsertItem(player);
  463. yield return 0;
  464. player.Collision.Disabled = false;
  465. GameApplication.Instance.Cursor.SetGuiMode(false);
  466. //派发进入地牢事件
  467. EventManager.EmitEvent(EventEnum.OnEnterDungeon);
  468. IsInDungeon = true;
  469. QueueRedraw();
  470. yield return 0;
  471. if (finish != null)
  472. {
  473. finish();
  474. }
  475. }
  476.  
  477. //执行退出地牢流程
  478. private IEnumerator RunExitDungeonCoroutine(bool keepPlayer, Action finish)
  479. {
  480. yield return 0;
  481. CurrWorld.Pause = true;
  482. yield return 0;
  483. _dungeonGenerator?.EachRoom(DisposeRoomInfo);
  484. yield return 0;
  485. _dungeonTileMap = null;
  486. AutoTileConfig = null;
  487. _dungeonGenerator = null;
  488. UiManager.Destroy_RoomUI();
  489. yield return 0;
  490. if (!keepPlayer)
  491. {
  492. Player.SetCurrentPlayer(null);
  493. }
  494. else
  495. {
  496. var player = Player.Current;
  497. player.AffiliationArea?.RemoveItem(player);
  498. player.GetParent().RemoveChild(player);
  499. player.World = null;
  500. player.Collision.Disabled = true;
  501. }
  502.  
  503. DestroyWorld();
  504. yield return 0;
  505. FogMaskHandler.ClearRecordRoom();
  506. LiquidBrushManager.ClearData();
  507. BrushImageData.ClearBrushData();
  508. QueueRedraw();
  509. //鼠标还原
  510. GameApplication.Instance.Cursor.SetGuiMode(true);
  511. //派发退出地牢事件
  512. EventManager.EmitEvent(EventEnum.OnExitDungeon);
  513. yield return 0;
  514. if (finish != null)
  515. {
  516. finish();
  517. }
  518. }
  519.  
  520. // 初始化房间
  521. private void InitRoom(RoomInfo roomInfo)
  522. {
  523. roomInfo.CalcRange();
  524. //创建门
  525. CreateDoor(roomInfo);
  526. //创建房间归属区域
  527. CreateRoomAffiliation(roomInfo);
  528. //创建 RoomStaticSprite
  529. CreateRoomStaticSprite(roomInfo);
  530. //创建静态精灵画布
  531. CreateRoomStaticImageCanvas(roomInfo);
  532. //创建液体区域
  533. CreateRoomLiquidCanvas(roomInfo);
  534. //创建迷雾遮罩
  535. CreateRoomFogMask(roomInfo);
  536. //创建房间/过道预览sprite
  537. CreatePreviewSprite(roomInfo);
  538. }
  539.  
  540. //创建门
  541. private void CreateDoor(RoomInfo roomInfo)
  542. {
  543. foreach (var doorInfo in roomInfo.Doors)
  544. {
  545. RoomDoor door;
  546. switch (doorInfo.Direction)
  547. {
  548. case DoorDirection.E:
  549. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_e);
  550. door.Position = (doorInfo.OriginPosition + new Vector2(0.5f, 2)) * GameConfig.TileCellSize;
  551. break;
  552. case DoorDirection.W:
  553. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_w);
  554. door.Position = (doorInfo.OriginPosition + new Vector2(-0.5f, 2)) * GameConfig.TileCellSize;
  555. break;
  556. case DoorDirection.S:
  557. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_s);
  558. door.Position = (doorInfo.OriginPosition + new Vector2(2f, 1.5f)) * GameConfig.TileCellSize;
  559. break;
  560. case DoorDirection.N:
  561. door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_n);
  562. door.Position = (doorInfo.OriginPosition + new Vector2(2f, -0.5f)) * GameConfig.TileCellSize;
  563. break;
  564. default:
  565. return;
  566. }
  567. doorInfo.Door = door;
  568. door.Init(doorInfo);
  569. door.PutDown(RoomLayerEnum.YSortLayer, false);
  570. }
  571. }
  572.  
  573. //创建房间归属区域
  574. private void CreateRoomAffiliation(RoomInfo roomInfo)
  575. {
  576. var affiliation = new AffiliationArea();
  577. affiliation.Name = "AffiliationArea" + roomInfo.Id;
  578. affiliation.Init(roomInfo, new Rect2I(
  579. roomInfo.GetWorldPosition() + new Vector2I(GameConfig.TileCellSize * 2, GameConfig.TileCellSize * 3),
  580. (roomInfo.Size - new Vector2I(4, 5)) * GameConfig.TileCellSize));
  581. roomInfo.AffiliationArea = affiliation;
  582. CurrWorld.AffiliationAreaRoot.AddChild(affiliation);
  583. }
  584.  
  585. //创建 RoomStaticSprite
  586. private void CreateRoomStaticSprite(RoomInfo roomInfo)
  587. {
  588. var spriteRoot = new RoomStaticSprite(roomInfo);
  589. spriteRoot.Name = "SpriteRoot";
  590. World.Current.StaticSpriteRoot.AddChild(spriteRoot);
  591. roomInfo.StaticSprite = spriteRoot;
  592. }
  593. //创建液体画布
  594. private void CreateRoomLiquidCanvas(RoomInfo roomInfo)
  595. {
  596. var rect = roomInfo.CanvasRect;
  597.  
  598. var liquidCanvas = new LiquidCanvas(roomInfo, rect.Size.X, rect.Size.Y);
  599. liquidCanvas.Position = rect.Position;
  600. roomInfo.LiquidCanvas = liquidCanvas;
  601. roomInfo.StaticSprite.AddChild(liquidCanvas);
  602. }
  603.  
  604. //创建静态图像画布
  605. private void CreateRoomStaticImageCanvas(RoomInfo roomInfo)
  606. {
  607. var rect = roomInfo.CanvasRect;
  608.  
  609. var canvasSprite = new ImageCanvas(rect.Size.X, rect.Size.Y);
  610. canvasSprite.Position = rect.Position;
  611. roomInfo.StaticImageCanvas = canvasSprite;
  612. roomInfo.StaticSprite.AddChild(canvasSprite);
  613. }
  614.  
  615. //创建迷雾遮罩
  616. private void CreateRoomFogMask(RoomInfo roomInfo)
  617. {
  618. var roomFog = new FogMask();
  619. roomFog.Name = "FogMask" + roomFog.IsDestroyed;
  620. roomFog.InitFog(roomInfo.Position + new Vector2I(1, 0), roomInfo.Size - new Vector2I(2, 1));
  621. //roomFog.InitFog(roomInfo.Position + new Vector2I(1, 1), roomInfo.Size - new Vector2I(2, 2));
  622.  
  623. CurrWorld.FogMaskRoot.AddChild(roomFog);
  624. roomInfo.RoomFogMask = roomFog;
  625. //生成通道迷雾
  626. foreach (var roomDoorInfo in roomInfo.Doors)
  627. {
  628. //必须是正向门
  629. if (roomDoorInfo.IsForward)
  630. {
  631. Rect2I calcRect;
  632. Rect2I fogAreaRect;
  633. if (!roomDoorInfo.HasCross)
  634. {
  635. calcRect = roomDoorInfo.GetAisleRect();
  636. fogAreaRect = calcRect;
  637. if (roomDoorInfo.Direction == DoorDirection.E || roomDoorInfo.Direction == DoorDirection.W)
  638. {
  639. calcRect.Position += new Vector2I(2, 0);
  640. calcRect.Size -= new Vector2I(4, 0);
  641. }
  642. else
  643. {
  644. calcRect.Position += new Vector2I(0, 2);
  645. calcRect.Size -= new Vector2I(0, 5);
  646. }
  647. }
  648. else
  649. {
  650. var aisleRect = roomDoorInfo.GetCrossAisleRect();
  651. calcRect = aisleRect.CalcAisleRect();
  652. fogAreaRect = calcRect;
  653.  
  654. if (roomDoorInfo.Direction == DoorDirection.E)
  655. {
  656. if (roomDoorInfo.ConnectDoor.Direction == DoorDirection.N) //→↑
  657. {
  658. calcRect.Position += new Vector2I(2, 0);
  659. calcRect.Size -= new Vector2I(2, 4);
  660. }
  661. else //→↓
  662. {
  663. calcRect.Position += new Vector2I(2, 3);
  664. calcRect.Size -= new Vector2I(2, 3);
  665. }
  666. }
  667. else if (roomDoorInfo.Direction == DoorDirection.W)
  668. {
  669. if (roomDoorInfo.ConnectDoor.Direction == DoorDirection.N) //←↑
  670. {
  671. calcRect.Size -= new Vector2I(2, 4);
  672. }
  673. else //←↓
  674. {
  675. calcRect.Position += new Vector2I(0, 3);
  676. calcRect.Size -= new Vector2I(2, 3);
  677. }
  678. }
  679. else if (roomDoorInfo.Direction == DoorDirection.N)
  680. {
  681. if (roomDoorInfo.ConnectDoor.Direction == DoorDirection.E) //↑→
  682. {
  683. calcRect.Position += new Vector2I(2, -1);
  684. calcRect.Size -= new Vector2I(2, 2);
  685. }
  686. else //↑←
  687. {
  688. calcRect.Position += new Vector2I(0, -1);
  689. calcRect.Size -= new Vector2I(2, 2);
  690. }
  691. }
  692. else if (roomDoorInfo.Direction == DoorDirection.S)
  693. {
  694. if (roomDoorInfo.ConnectDoor.Direction == DoorDirection.E) //↓→
  695. {
  696. calcRect.Position += new Vector2I(2, 2);
  697. calcRect.Size -= new Vector2I(2, 1);
  698. }
  699. else //↓←
  700. {
  701. calcRect.Position += new Vector2I(0, 2);
  702. calcRect.Size -= new Vector2I(2, 1);
  703. }
  704. }
  705. }
  706.  
  707. //过道迷雾遮罩
  708. var aisleFog = new FogMask();
  709. var calcRectSize = calcRect.Size;
  710. var calcRectPosition = calcRect.Position;
  711. if (roomDoorInfo.Direction == DoorDirection.N || roomDoorInfo.Direction == DoorDirection.S)
  712. {
  713. calcRectSize.Y -= 1;
  714. }
  715. else
  716. {
  717. calcRectPosition.Y -= 1;
  718. calcRectSize.Y += 1;
  719. }
  720.  
  721. aisleFog.InitFog(calcRectPosition, calcRectSize);
  722. CurrWorld.FogMaskRoot.AddChild(aisleFog);
  723. roomDoorInfo.AisleFogMask = aisleFog;
  724. roomDoorInfo.ConnectDoor.AisleFogMask = aisleFog;
  725.  
  726. //过道迷雾区域
  727. var fogArea = new AisleFogArea();
  728. fogArea.Init(roomDoorInfo,
  729. new Rect2I(
  730. fogAreaRect.Position * GameConfig.TileCellSize,
  731. fogAreaRect.Size * GameConfig.TileCellSize
  732. )
  733. );
  734. roomDoorInfo.AisleFogArea = fogArea;
  735. roomDoorInfo.ConnectDoor.AisleFogArea = fogArea;
  736. CurrWorld.AffiliationAreaRoot.AddChild(fogArea);
  737. }
  738.  
  739. //预览迷雾区域
  740. var previewRoomFog = new PreviewFogMask();
  741. roomDoorInfo.PreviewRoomFogMask = previewRoomFog;
  742. previewRoomFog.Init(roomDoorInfo, PreviewFogMask.PreviewFogType.Room);
  743. previewRoomFog.SetActive(false);
  744. CurrWorld.FogMaskRoot.AddChild(previewRoomFog);
  745. var previewAisleFog = new PreviewFogMask();
  746. roomDoorInfo.PreviewAisleFogMask = previewAisleFog;
  747. previewAisleFog.Init(roomDoorInfo, PreviewFogMask.PreviewFogType.Aisle);
  748. previewAisleFog.SetActive(false);
  749. CurrWorld.FogMaskRoot.AddChild(previewAisleFog);
  750. }
  751. }
  752.  
  753. private void CreatePreviewSprite(RoomInfo roomInfo)
  754. {
  755. //房间区域
  756. var sprite = new TextureRect();
  757. //sprite.Centered = false;
  758. sprite.Texture = roomInfo.PreviewTexture;
  759. sprite.Position = roomInfo.Position + new Vector2I(1, 3);
  760. var material = ResourceManager.Load<ShaderMaterial>(ResourcePath.resource_material_Outline2_tres, false);
  761. material.SetShaderParameter("outline_color", new Color(1, 1, 1, 0.9f));
  762. material.SetShaderParameter("scale", 0.5f);
  763. sprite.Material = material;
  764. roomInfo.PreviewSprite = sprite;
  765. //过道
  766. if (roomInfo.Doors != null)
  767. {
  768. foreach (var doorInfo in roomInfo.Doors)
  769. {
  770. if (doorInfo.IsForward)
  771. {
  772. var aisleSprite = new TextureRect();
  773. //aisleSprite.Centered = false;
  774. aisleSprite.Texture = doorInfo.AislePreviewTexture;
  775. //调整过道预览位置
  776. if (doorInfo.Direction == DoorDirection.N || doorInfo.Direction == DoorDirection.S ||
  777. doorInfo.ConnectDoor.Direction == DoorDirection.N || doorInfo.ConnectDoor.Direction == DoorDirection.S)
  778. {
  779. aisleSprite.Position = doorInfo.AisleFloorRect.Position + new Vector2I(0, 1);
  780. }
  781. else
  782. {
  783. aisleSprite.Position = doorInfo.AisleFloorRect.Position;
  784. }
  785.  
  786. // var aisleSpriteMaterial = ResourceManager.Load<ShaderMaterial>(ResourcePath.resource_material_Outline2_tres, false);
  787. // aisleSpriteMaterial.SetShaderParameter("outline_color", new Color(1, 1, 1, 0.9f));
  788. // aisleSpriteMaterial.SetShaderParameter("scale", 0.5f);
  789. // aisleSprite.Material = aisleSpriteMaterial;
  790. doorInfo.AislePreviewSprite = aisleSprite;
  791. doorInfo.ConnectDoor.AislePreviewSprite = aisleSprite;
  792. }
  793. }
  794. }
  795. }
  796. /// <summary>
  797. /// 玩家第一次进入某个房间回调
  798. /// </summary>
  799. private void OnPlayerFirstEnterRoom(object o)
  800. {
  801. var room = (RoomInfo)o;
  802. room.OnFirstEnter();
  803. //如果关门了, 那么房间外的敌人就会丢失目标
  804. if (room.IsSeclusion)
  805. {
  806. var playerAffiliationArea = Player.Current.AffiliationArea;
  807. foreach (var enemy in CurrWorld.Enemy_InstanceList)
  808. {
  809. //不与玩家处于同一个房间
  810. if (!enemy.IsDestroyed && enemy.AffiliationArea != playerAffiliationArea)
  811. {
  812. if (enemy.StateController.CurrState != AIStateEnum.AiNormal)
  813. {
  814. enemy.StateController.ChangeState(AIStateEnum.AiNormal);
  815. }
  816. }
  817. }
  818. }
  819. }
  820.  
  821. /// <summary>
  822. /// 玩家进入某个房间回调
  823. /// </summary>
  824. private void OnPlayerEnterRoom(object o)
  825. {
  826. var roomInfo = (RoomInfo)o;
  827. if (_affiliationAreaFlag != roomInfo.AffiliationArea)
  828. {
  829. if (!roomInfo.AffiliationArea.IsDestroyed)
  830. {
  831. //刷新迷雾
  832. FogMaskHandler.RefreshRoomFog(roomInfo);
  833. }
  834.  
  835. _affiliationAreaFlag = roomInfo.AffiliationArea;
  836. }
  837. }
  838. /// <summary>
  839. /// 检测当前房间敌人是否已经消灭干净, 应当每秒执行一次
  840. /// </summary>
  841. private void OnCheckEnemy()
  842. {
  843. var activeRoom = ActiveRoomInfo;
  844. if (activeRoom != null && activeRoom.RoomPreinstall != null)
  845. {
  846. if (activeRoom.RoomPreinstall.IsRunWave) //正在生成标记
  847. {
  848. if (activeRoom.RoomPreinstall.IsCurrWaveOver()) //所有标记执行完成
  849. {
  850. //房间内是否有存活的敌人
  851. var flag = ActiveAffiliationArea.ExistEnterItem(
  852. activityObject => activityObject.CollisionWithMask(PhysicsLayer.Enemy)
  853. );
  854. //Debug.Log("当前房间存活数量: " + count);
  855. if (!flag)
  856. {
  857. activeRoom.OnClearRoom();
  858. }
  859. }
  860. }
  861. }
  862. }
  863.  
  864. private void DisposeRoomInfo(RoomInfo roomInfo)
  865. {
  866. roomInfo.Destroy();
  867. }
  868. public override void _Draw()
  869. {
  870. if (ActivityObject.IsDebug)
  871. {
  872. StartRoomInfo?.EachRoom(info =>
  873. {
  874. DrawRect(new Rect2(info.Waypoints * GameConfig.TileCellSize, new Vector2(16, 16)), Colors.Red);
  875. });
  876. //绘制房间区域
  877. if (_dungeonGenerator != null)
  878. {
  879. DrawRoomInfo(StartRoomInfo);
  880. }
  881. //绘制边缘线
  882.  
  883. }
  884. }
  885. //绘制房间区域, debug 用
  886. private void DrawRoomInfo(RoomInfo roomInfo)
  887. {
  888. var cellSize = GameConfig.TileCellSize;
  889. var pos1 = (roomInfo.Position + roomInfo.Size / 2) * cellSize;
  890. //绘制下一个房间
  891. foreach (var nextRoom in roomInfo.Next)
  892. {
  893. var pos2 = (nextRoom.Position + nextRoom.Size / 2) * cellSize;
  894. DrawLine(pos1, pos2, Colors.Red);
  895. DrawRoomInfo(nextRoom);
  896. }
  897.  
  898. DrawString(ResourceManager.DefaultFont16Px, pos1 - new Vector2I(0, 10), "Id: " + roomInfo.Id.ToString());
  899. DrawString(ResourceManager.DefaultFont16Px, pos1 + new Vector2I(0, 10), "Layer: " + roomInfo.Layer.ToString());
  900.  
  901. //绘制门
  902. foreach (var roomDoor in roomInfo.Doors)
  903. {
  904. var originPos = roomDoor.OriginPosition * cellSize;
  905. switch (roomDoor.Direction)
  906. {
  907. case DoorDirection.E:
  908. DrawLine(originPos, originPos + new Vector2(3, 0) * cellSize, Colors.Yellow);
  909. DrawLine(originPos + new Vector2(0, 4) * cellSize, originPos + new Vector2(3, 4) * cellSize,
  910. Colors.Yellow);
  911. break;
  912. case DoorDirection.W:
  913. DrawLine(originPos, originPos - new Vector2(3, 0) * cellSize, Colors.Yellow);
  914. DrawLine(originPos + new Vector2(0, 4) * cellSize, originPos - new Vector2(3, -4) * cellSize,
  915. Colors.Yellow);
  916. break;
  917. case DoorDirection.S:
  918. DrawLine(originPos, originPos + new Vector2(0, 3) * cellSize, Colors.Yellow);
  919. DrawLine(originPos + new Vector2(4, 0) * cellSize, originPos + new Vector2(4, 3) * cellSize,
  920. Colors.Yellow);
  921. break;
  922. case DoorDirection.N:
  923. DrawLine(originPos, originPos - new Vector2(0, 3) * cellSize, Colors.Yellow);
  924. DrawLine(originPos + new Vector2(4, 0) * cellSize, originPos - new Vector2(-4, 3) * cellSize,
  925. Colors.Yellow);
  926. break;
  927. }
  928. //绘制房间区域
  929. DrawRect(new Rect2(roomInfo.Position * cellSize, roomInfo.Size * cellSize), Colors.Blue, false);
  930.  
  931. if (roomDoor.HasCross && roomDoor.RoomInfo.Id < roomDoor.ConnectRoom.Id)
  932. {
  933. DrawRect(new Rect2(roomDoor.Cross * cellSize, new Vector2(cellSize * 4, cellSize * 4)), Colors.Yellow, false);
  934. }
  935. }
  936. }
  937. /// <summary>
  938. /// 将房间类型枚举转为字符串
  939. /// </summary>
  940. public static string DungeonRoomTypeToString(DungeonRoomType roomType)
  941. {
  942. switch (roomType)
  943. {
  944. case DungeonRoomType.Battle: return "battle";
  945. case DungeonRoomType.Inlet: return "inlet";
  946. case DungeonRoomType.Outlet: return "outlet";
  947. case DungeonRoomType.Boss: return "boss";
  948. case DungeonRoomType.Reward: return "reward";
  949. case DungeonRoomType.Shop: return "shop";
  950. case DungeonRoomType.Event: return "event";
  951. }
  952.  
  953. return "battle";
  954. }
  955. /// <summary>
  956. /// 将房间类型枚举转为描述字符串
  957. /// </summary>
  958. public static string DungeonRoomTypeToDescribeString(DungeonRoomType roomType)
  959. {
  960. switch (roomType)
  961. {
  962. case DungeonRoomType.Battle: return "战斗房间";
  963. case DungeonRoomType.Inlet: return "起始房间";
  964. case DungeonRoomType.Outlet: return "结束房间";
  965. case DungeonRoomType.Boss: return "Boss房间";
  966. case DungeonRoomType.Reward: return "奖励房间";
  967. case DungeonRoomType.Shop: return "商店房间";
  968. case DungeonRoomType.Event: return "事件房间";
  969. }
  970.  
  971. return "战斗房间";
  972. }
  973.  
  974. /// <summary>
  975. /// 检测地牢是否可以执行生成
  976. /// </summary>
  977. /// <param name="groupName">组名称</param>
  978. public static DungeonCheckState CheckDungeon(string groupName)
  979. {
  980. if (GameApplication.Instance.RoomConfig.TryGetValue(groupName, out var group))
  981. {
  982. //验证该组是否满足生成地牢的条件
  983. if (group.InletList.Count == 0)
  984. {
  985. return new DungeonCheckState(true, "当没有可用的起始房间!");
  986. }
  987. else if (group.OutletList.Count == 0)
  988. {
  989. return new DungeonCheckState(true, "没有可用的结束房间!");
  990. }
  991. else if (group.BattleList.Count == 0)
  992. {
  993. return new DungeonCheckState(true, "没有可用的战斗房间!");
  994. }
  995.  
  996. return new DungeonCheckState(false, null);
  997. }
  998.  
  999. return new DungeonCheckState(true, "未找到地牢组");
  1000. }
  1001. }