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