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