using System; using System.Collections; using Config; using Godot; /// <summary> /// 地牢管理器 /// </summary> public partial class DungeonManager : Node2D { /// <summary> /// 起始房间 /// </summary> public RoomInfo StartRoomInfo => _dungeonGenerator?.StartRoomInfo; /// <summary> /// 当前玩家所在的房间 /// </summary> public RoomInfo ActiveRoomInfo => CurrWorld.Player?.AffiliationArea?.RoomInfo; /// <summary> /// 当前玩家所在的区域 /// </summary> public AffiliationArea ActiveAffiliationArea => CurrWorld.Player?.AffiliationArea; /// <summary> /// 是否在地牢里 /// </summary> public bool IsInDungeon { get; private set; } /// <summary> /// 是否是编辑器模式 /// </summary> public bool IsEditorMode { get; private set; } /// <summary> /// 当前使用的配置 /// </summary> public DungeonConfig CurrConfig { get; private set; } /// <summary> /// 当前玩家所在游戏世界对象 /// </summary> public World CurrWorld { get; private set; } /// <summary> /// 自动图块配置 /// </summary> public AutoTileConfig AutoTileConfig { get; private set; } /// <summary> /// 加载角色ID /// </summary> public string LoadRoleId { get; set; } private UiBase _prevUi; private DungeonTileMap _dungeonTileMap; private DungeonGenerator _dungeonGenerator; //用于检查房间敌人的计时器 private float _checkEnemyTimer = 0; //用于记录玩家上一个所在区域 private AffiliationArea _affiliationAreaFlag; private Role _cachePlayer; public DungeonManager(string loadRoleId) { LoadRoleId = loadRoleId; //绑定事件 EventManager.AddEventListener(EventEnum.OnPlayerFirstEnterRoom, OnPlayerFirstEnterRoom); EventManager.AddEventListener(EventEnum.OnPlayerEnterRoom, OnPlayerEnterRoom); } /// <summary> /// 创建新的 World 对象, 相当于清理房间 /// </summary> public World CreateNewWorld(SeedRandom random, string scenePath) { if (CurrWorld != null) { ClearWorld(); CurrWorld.QueueFree(); } CurrWorld = ResourceManager.LoadAndInstantiate<World>(scenePath); GameApplication.Instance.SceneRoot.AddChild(CurrWorld); CurrWorld.InitRandomPool(random); return CurrWorld; } /// <summary> /// 销毁 World 对象, 相当于清理房间 /// </summary> public void DestroyWorld() { //销毁所有物体 if (CurrWorld != null) { ClearWorld(); CurrWorld.QueueFree(); } //销毁池中所有物体 ObjectPool.DisposeAllItem(); CurrWorld = null; } //清理世界 private void ClearWorld() { var childCount = CurrWorld.NormalLayer.GetChildCount(); for (var i = 0; i < childCount; i++) { var c = CurrWorld.NormalLayer.GetChild(i); if (c is IDestroy destroy) { destroy.Destroy(); } } childCount = CurrWorld.YSortLayer.GetChildCount(); for (var i = 0; i < childCount; i++) { var c = CurrWorld.YSortLayer.GetChild(i); if (c is IDestroy destroy) { destroy.Destroy(); } } } /// <summary> /// 进入大厅 /// </summary> public void LoadHall(Action finish = null) { GameApplication.Instance.StartCoroutine(RunLoadHallCoroutine(finish)); } /// <summary> /// 退出大厅 /// </summary> public void ExitHall(bool keepPlayer, Action finish = null) { GameApplication.Instance.StartCoroutine(RunExitHallCoroutine(keepPlayer, finish)); } /// <summary> /// 加载地牢 /// </summary> public void LoadDungeon(DungeonConfig config, Action finish = null) { IsEditorMode = false; CurrConfig = config; GameApplication.Instance.StartCoroutine(RunLoadDungeonCoroutine(finish)); } /// <summary> /// 重启地牢 /// </summary> public void RestartDungeon(bool keepPlayer, DungeonConfig config, Action finish = null) { IsEditorMode = false; CurrConfig = config; ExitDungeon(keepPlayer, () => { LoadDungeon(CurrConfig, finish); }); } /// <summary> /// 退出地牢 /// </summary> public void ExitDungeon(bool keepPlayer, Action finish = null) { IsInDungeon = false; GameApplication.Instance.StartCoroutine(RunExitDungeonCoroutine(keepPlayer, finish)); } //------------------------------------------------------------------------------------- /// <summary> /// 在编辑器模式下进入地牢 /// </summary> /// <param name="config">地牢配置</param> /// <param name="finish">执行完成回调</param> public void EditorPlayDungeon(DungeonConfig config, Action finish = null) { IsEditorMode = true; CurrConfig = config; if (_prevUi != null) { _prevUi.HideUi(); } GameApplication.Instance.StartCoroutine(RunLoadDungeonCoroutine(finish)); } /// <summary> /// 在编辑器模式下进入地牢 /// </summary> /// <param name="prevUi">记录上一个Ui</param> /// <param name="config">地牢配置</param> /// <param name="finish">执行完成回调</param> public void EditorPlayDungeon(UiBase prevUi, DungeonConfig config, Action finish = null) { IsEditorMode = true; CurrConfig = config; _prevUi = prevUi; if (_prevUi != null) { _prevUi.HideUi(); } GameApplication.Instance.StartCoroutine(RunLoadDungeonCoroutine(finish)); } /// <summary> /// 在编辑器模式下退出地牢, 并且打开上一个Ui /// </summary> public void EditorExitDungeon(bool keepPlayer, Action finish = null) { IsInDungeon = false; GameApplication.Instance.StartCoroutine(RunExitDungeonCoroutine(keepPlayer, () => { IsEditorMode = false; //显示上一个Ui if (_prevUi != null) { _prevUi.ShowUi(); } if (finish != null) { finish(); } })); } //------------------------------------------------------------------------------------- public override void _Process(double delta) { if (IsInDungeon) { if (CurrWorld.Pause) //已经暂停 { return; } //暂停游戏 if (InputManager.Menu) { CurrWorld.Pause = true; //鼠标改为Ui鼠标 GameApplication.Instance.Cursor.SetGuiMode(true); //打开暂停Ui UiManager.Open_PauseMenu(); } //更新迷雾 FogMaskHandler.Update(); _checkEnemyTimer += (float)delta; if (_checkEnemyTimer >= 1) { _checkEnemyTimer %= 1; //检查房间内的敌人存活状况 OnCheckEnemy(); } if (ActivityObject.IsDebug) { QueueRedraw(); } } } //执行加载大厅流程 private IEnumerator RunLoadHallCoroutine(Action finish) { yield return 0; var hall = (Hall)CreateNewWorld(Utils.Random, ResourcePath.scene_Hall_tscn); yield return 0; //创建房间数据 var roomInfo = new RoomInfo(0, DungeonRoomType.None, null); roomInfo.World = CurrWorld; roomInfo.Size = hall.BgSprite.Texture.GetSize().AsVector2I() / GameConfig.TileCellSize + new Vector2I(10, 10); roomInfo.Position = hall.BgSprite.Position.AsVector2I() - new Vector2I(5, 5) * GameConfig.TileCellSize; hall.RoomInfo = roomInfo; yield return 0; //创建归属区域 var affiliation = new AffiliationArea(); affiliation.Name = "AffiliationArea_Hall"; affiliation.Init(roomInfo, new Rect2I(roomInfo.Position, roomInfo.Size * GameConfig.TileCellSize)); roomInfo.AffiliationArea = affiliation; hall.AffiliationAreaRoot.AddChild(affiliation); yield return 0; //静态渲染精灵根节点, 用于放置sprite var spriteRoot = new RoomStaticSprite(roomInfo); spriteRoot.Name = "SpriteRoot"; roomInfo.StaticSprite = spriteRoot; hall.StaticSpriteRoot.AddChild(spriteRoot); yield return 0; //静态精灵画布 var canvasSprite = new ImageCanvas(roomInfo.Size.X * GameConfig.TileCellSize, roomInfo.Size.Y * GameConfig.TileCellSize); canvasSprite.Position = roomInfo.Position; roomInfo.StaticImageCanvas = canvasSprite; roomInfo.StaticSprite.AddChild(canvasSprite); yield return 0; //液体画布 var liquidCanvas = new LiquidCanvas(roomInfo, roomInfo.Size.X * GameConfig.TileCellSize, roomInfo.Size.Y * GameConfig.TileCellSize); liquidCanvas.Position = roomInfo.Position; roomInfo.LiquidCanvas = liquidCanvas; roomInfo.StaticSprite.AddChild(liquidCanvas); yield return 0; //打开游戏中的ui UiManager.Open_RoomUI(); yield return 0; //创建玩家 var player = CurrWorld.Player; if (player == null) { player = ActivityObject.Create<Player>(ActivityObject.Ids.Id_role0001); player.Name = "Player"; } player.World = CurrWorld; player.Position = hall.BirthMark.Position; player.PutDown(RoomLayerEnum.YSortLayer); CurrWorld.SetCurrentPlayer(player); affiliation.InsertItem(player); player.WeaponPack.PickupItem(ActivityObject.Create<Weapon>(ActivityObject.Ids.Id_weapon0001)); yield return 0; player.Collision.Disabled = false; GameApplication.Instance.Cursor.SetGuiMode(false); yield return 0; IsInDungeon = true; if (finish != null) { finish(); } } //执行退出大厅流程 private IEnumerator RunExitHallCoroutine(bool keepPlayer, Action finish) { IsInDungeon = false; yield return 0; CurrWorld.Pause = true; yield return 0; var hall = (Hall)CurrWorld; hall.RoomInfo.Destroy(); yield return 0; UiManager.Destroy_RoomUI(); yield return 0; if (!keepPlayer) { CurrWorld.SetCurrentPlayer(null); } else { var player = CurrWorld.Player; player.AffiliationArea?.RemoveItem(player); player.GetParent().RemoveChild(player); player.World = null; player.Collision.Disabled = true; } CurrWorld.OnUnloadSuccess(); DestroyWorld(); yield return 0; FogMaskHandler.ClearRecordRoom(); LiquidBrushManager.ClearData(); BrushImageData.ClearBrushData(); QueueRedraw(); yield return 0; //鼠标还原 GameApplication.Instance.Cursor.SetGuiMode(true); yield return 0; if (finish != null) { finish(); } } //执行加载地牢协程 private IEnumerator RunLoadDungeonCoroutine(Action finish) { yield return 0; //生成地牢房间 //最多尝试10次 const int maxCount = 10; for (var i = 0; i < maxCount; i++) { SeedRandom random; if (CurrConfig.RandomSeed != null) { random = new SeedRandom(CurrConfig.RandomSeed.Value); } else { random = new SeedRandom(); } var dungeonGenerator = new DungeonGenerator(CurrConfig, random); var rule = new DefaultDungeonRule(dungeonGenerator); if (!dungeonGenerator.Generate(rule)) //生成房间失败 { dungeonGenerator.EachRoom(DisposeRoomInfo); if (i == maxCount - 1) { if (IsEditorMode) //在编辑器模式下打开的Ui { EditorPlayManager.IsPlay = false; IsEditorMode = false; //显示上一个Ui if (_prevUi != null) { _prevUi.ShowUi(); //尝试关闭加载Ui UiManager.Destroy_Loading(); } } else //正常关闭Ui { UiManager.Open_Main(); //尝试关闭加载Ui UiManager.Destroy_Loading(); } EditorWindowManager.ShowTips("错误", "生成房间尝试次数过多,生成地牢房间失败,请加大房间门连接区域,或者修改地牢生成规则!"); yield break; } else { yield return 0; } } else //生成成功! { _dungeonGenerator = dungeonGenerator; break; } } yield return 0; //创建世界场景 var dungeon = (Dungeon)CreateNewWorld(_dungeonGenerator.Random, ResourcePath.scene_Dungeon_tscn); dungeon.DungeonConfig = _dungeonGenerator.Config; dungeon.RoomGroup = _dungeonGenerator.RoomGroup; dungeon.InitLayer(); //初始化房间 World 字段 foreach (var roomInfo in _dungeonGenerator.RoomInfos) { roomInfo.World = dungeon; } yield return 0; var group = GameApplication.Instance.RoomConfig[CurrConfig.GroupName]; var tileSetSplit = GameApplication.Instance.TileSetConfig[group.TileSet]; CurrWorld.TileRoot.TileSet = tileSetSplit.GetTileSet(); //填充地牢 AutoTileConfig = new AutoTileConfig(0, tileSetSplit.TileSetInfo.Sources[0].Terrain[0]); _dungeonTileMap = new DungeonTileMap(CurrWorld.TileRoot); yield return _dungeonTileMap.AutoFillRoomTile(AutoTileConfig, _dungeonGenerator.StartRoomInfo, CurrWorld); yield return _dungeonTileMap.AutoFillAisleTile(AutoTileConfig, _dungeonGenerator.StartRoomInfo, CurrWorld); //yield return _dungeonTileMap.AddOutlineTile(AutoTileConfig.WALL_BLOCK); yield return 0; //生成墙壁, 生成导航网格 _dungeonTileMap.GenerateWallAndNavigation(CurrWorld, AutoTileConfig); yield return 0; //初始化所有房间 yield return _dungeonGenerator.EachRoomCoroutine(InitRoom); //Debug.Log("[临时处理]: 关闭房间迷雾"); //CurrWorld.FogMaskRoot.Visible = false; //房间背景颜色 RenderingServer.SetDefaultClearColor(_dungeonGenerator.RoomGroup.BgColor); //播放bgm if (!string.IsNullOrEmpty(_dungeonGenerator.RoomGroup.SoundId) && ExcelConfig.Sound_Map.ContainsKey(_dungeonGenerator.RoomGroup.SoundId)) { CurrWorld.PlayBgm(_dungeonGenerator.RoomGroup.SoundId); } GameCamera.Main.FollowsMouseAmount = 0.15f; //地牢加载即将完成 yield return _dungeonGenerator.EachRoomCoroutine(info => info.OnReady()); //打开游戏中的ui UiManager.Open_RoomUI(); yield return 0; //创建自定义物体 _dungeonGenerator.EachRoom(OnInitCustomObject); yield return 0; //初始房间创建玩家标记 var playerBirthMark = StartRoomInfo.RoomPreinstall.GetSpecialMark(SpecialMarkType.BirthPoint); //创建玩家 var player = CurrWorld.Player ?? _cachePlayer; if (player == null) { player = ActivityObject.Create<Role>(LoadRoleId); player.Name = "Player"; } if (playerBirthMark != null) { player.Position = playerBirthMark.Position; } _cachePlayer = null; player.World = CurrWorld; player.PutDown(RoomLayerEnum.YSortLayer); CurrWorld.SetCurrentPlayer(player); StartRoomInfo.AffiliationArea.InsertItem(player); yield return 0; player.Collision.Disabled = false; GameCamera.Main.Zoom = Vector2.One; GameApplication.Instance.Cursor.SetGuiMode(false); //派发进入地牢事件 EventManager.EmitEvent(EventEnum.OnEnterDungeon); IsInDungeon = true; QueueRedraw(); yield return 0; CurrWorld.OnLoadSuccess(); if (finish != null) { finish(); } } //执行退出地牢流程 private IEnumerator RunExitDungeonCoroutine(bool keepPlayer, Action finish) { yield return 0; CurrWorld.Pause = true; yield return 0; _dungeonGenerator?.EachRoom(DisposeRoomInfo); yield return 0; _dungeonTileMap = null; AutoTileConfig = null; _dungeonGenerator = null; UiManager.Destroy_RoomUI(); yield return 0; if (!keepPlayer) { CurrWorld.SetCurrentPlayer(null); if (_cachePlayer != null) { _cachePlayer.Destroy(); _cachePlayer = null; } } else { var player = CurrWorld.Player; player.AffiliationArea?.RemoveItem(player); player.GetParent().RemoveChild(player); player.World = null; player.Collision.Disabled = true; _cachePlayer = player; } yield return 0; CurrWorld.OnUnloadSuccess(); DestroyWorld(); yield return 0; //还原房间背景颜色 RenderingServer.SetDefaultClearColor(Colors.Black); FogMaskHandler.ClearRecordRoom(); LiquidBrushManager.ClearData(); BrushImageData.ClearBrushData(); QueueRedraw(); //鼠标还原 GameApplication.Instance.Cursor.SetGuiMode(true); //派发退出地牢事件 EventManager.EmitEvent(EventEnum.OnExitDungeon); yield return 0; if (finish != null) { finish(); } } //初始化自定义物体 private void OnInitCustomObject(RoomInfo info) { var tileInfo = info.RoomSplit.TileInfo; if (tileInfo.NormalLayerObjects != null) { foreach (var objectInfo in tileInfo.NormalLayerObjects) { CreateCustomObject(info, objectInfo, RoomLayerEnum.NormalLayer); } } if (tileInfo.YSortLayerObjects != null) { foreach (var objectInfo in tileInfo.YSortLayerObjects) { CreateCustomObject(info, objectInfo, RoomLayerEnum.YSortLayer); } } } private void CreateCustomObject(RoomInfo roomInfo, RoomObjectInfo info, RoomLayerEnum layer) { if (ExcelConfig.EditorObject_Map.TryGetValue(info.Id, out var editorObject)) { if (editorObject.IsActivity()) { var activityObject = ActivityObject.Create(editorObject.Prefab); activityObject.Position = roomInfo.ToGlobalPosition(new Vector2(info.X, info.Y)); activityObject.PutDown(layer); } else { var node = ResourceManager.LoadAndInstantiate<Node2D>(editorObject.Prefab); node.Position = roomInfo.ToGlobalPosition(new Vector2(info.X, info.Y)); node.AddToActivityRoot(layer); } } else { Debug.LogError($"创建CustomObject没有找到物体配置: {info.Id}!"); } } // 初始化房间 private void InitRoom(RoomInfo roomInfo) { roomInfo.CalcRange(); //创建门 CreateDoor(roomInfo); //创建房间归属区域 CreateRoomAffiliation(roomInfo); //创建 RoomStaticSprite CreateRoomStaticSprite(roomInfo); //创建静态精灵画布 CreateRoomStaticImageCanvas(roomInfo); //创建液体区域 CreateRoomLiquidCanvas(roomInfo); //创建迷雾遮罩 CreateRoomFogMask(roomInfo); //创建房间/过道预览sprite CreatePreviewSprite(roomInfo); } //创建门 private void CreateDoor(RoomInfo roomInfo) { foreach (var doorInfo in roomInfo.Doors) { RoomDoor door; switch (doorInfo.Direction) { case DoorDirection.E: door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_e); door.Position = (doorInfo.OriginPosition + new Vector2(0.5f, 2)) * GameConfig.TileCellSize; break; case DoorDirection.W: door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_w); door.Position = (doorInfo.OriginPosition + new Vector2(-0.5f, 2)) * GameConfig.TileCellSize; break; case DoorDirection.S: door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_s); door.Position = (doorInfo.OriginPosition + new Vector2(2f, 1.5f)) * GameConfig.TileCellSize; break; case DoorDirection.N: door = ActivityObject.Create<RoomDoor>(ActivityObject.Ids.Id_other_door_n); door.Position = (doorInfo.OriginPosition + new Vector2(2f, -0.5f)) * GameConfig.TileCellSize; break; default: return; } doorInfo.Door = door; door.Init(doorInfo); door.PutDown(RoomLayerEnum.YSortLayer, false); } } //创建房间归属区域 private void CreateRoomAffiliation(RoomInfo roomInfo) { var affiliation = new AffiliationArea(); affiliation.Name = "AffiliationArea" + roomInfo.Id; affiliation.Init(roomInfo, new Rect2I( roomInfo.GetWorldPosition() + new Vector2I(GameConfig.TileCellSize * 2, GameConfig.TileCellSize * 3), (roomInfo.Size - new Vector2I(4, 5)) * GameConfig.TileCellSize)); roomInfo.AffiliationArea = affiliation; CurrWorld.AffiliationAreaRoot.AddChild(affiliation); } //创建 RoomStaticSprite private void CreateRoomStaticSprite(RoomInfo roomInfo) { var spriteRoot = new RoomStaticSprite(roomInfo); spriteRoot.Name = "SpriteRoot"; World.Current.StaticSpriteRoot.AddChild(spriteRoot); roomInfo.StaticSprite = spriteRoot; } //创建液体画布 private void CreateRoomLiquidCanvas(RoomInfo roomInfo) { var rect = roomInfo.CanvasRect; var liquidCanvas = new LiquidCanvas(roomInfo, rect.Size.X, rect.Size.Y); liquidCanvas.Position = rect.Position; roomInfo.LiquidCanvas = liquidCanvas; roomInfo.StaticSprite.AddChild(liquidCanvas); } //创建静态图像画布 private void CreateRoomStaticImageCanvas(RoomInfo roomInfo) { var rect = roomInfo.CanvasRect; var canvasSprite = new ImageCanvas(rect.Size.X, rect.Size.Y); canvasSprite.Position = rect.Position; roomInfo.StaticImageCanvas = canvasSprite; roomInfo.StaticSprite.AddChild(canvasSprite); } //创建迷雾遮罩 private void CreateRoomFogMask(RoomInfo roomInfo) { var roomFog = new FogMask(); roomFog.Name = "FogMask" + roomFog.IsDestroyed; roomFog.InitFog(roomInfo.Position + new Vector2I(1, 0), roomInfo.Size - new Vector2I(2, 1)); //roomFog.InitFog(roomInfo.Position + new Vector2I(1, 1), roomInfo.Size - new Vector2I(2, 2)); CurrWorld.FogMaskRoot.AddChild(roomFog); roomInfo.RoomFogMask = roomFog; //生成通道迷雾 foreach (var roomDoorInfo in roomInfo.Doors) { //必须是正向门 if (roomDoorInfo.IsForward) { Rect2I calcRect; Rect2I fogAreaRect; if (!roomDoorInfo.HasCross) { calcRect = roomDoorInfo.GetAisleRect(); fogAreaRect = calcRect; if (roomDoorInfo.Direction == DoorDirection.E || roomDoorInfo.Direction == DoorDirection.W) { calcRect.Position += new Vector2I(2, 0); calcRect.Size -= new Vector2I(4, 0); } else { calcRect.Position += new Vector2I(0, 2); calcRect.Size -= new Vector2I(0, 5); } } else { var aisleRect = roomDoorInfo.GetCrossAisleRect(); calcRect = aisleRect.CalcAisleRect(); fogAreaRect = calcRect; if (roomDoorInfo.Direction == DoorDirection.E) { if (roomDoorInfo.ConnectDoor.Direction == DoorDirection.N) //→↑ { calcRect.Position += new Vector2I(2, 0); calcRect.Size -= new Vector2I(2, 4); } else //→↓ { calcRect.Position += new Vector2I(2, 3); calcRect.Size -= new Vector2I(2, 3); } } else if (roomDoorInfo.Direction == DoorDirection.W) { if (roomDoorInfo.ConnectDoor.Direction == DoorDirection.N) //←↑ { calcRect.Size -= new Vector2I(2, 4); } else //←↓ { calcRect.Position += new Vector2I(0, 3); calcRect.Size -= new Vector2I(2, 3); } } else if (roomDoorInfo.Direction == DoorDirection.N) { if (roomDoorInfo.ConnectDoor.Direction == DoorDirection.E) //↑→ { calcRect.Position += new Vector2I(2, -1); calcRect.Size -= new Vector2I(2, 2); } else //↑← { calcRect.Position += new Vector2I(0, -1); calcRect.Size -= new Vector2I(2, 2); } } else if (roomDoorInfo.Direction == DoorDirection.S) { if (roomDoorInfo.ConnectDoor.Direction == DoorDirection.E) //↓→ { calcRect.Position += new Vector2I(2, 2); calcRect.Size -= new Vector2I(2, 1); } else //↓← { calcRect.Position += new Vector2I(0, 2); calcRect.Size -= new Vector2I(2, 1); } } } //过道迷雾遮罩 var aisleFog = new FogMask(); var calcRectSize = calcRect.Size; var calcRectPosition = calcRect.Position; if (roomDoorInfo.Direction == DoorDirection.N || roomDoorInfo.Direction == DoorDirection.S) { calcRectSize.Y -= 1; } else { calcRectPosition.Y -= 1; calcRectSize.Y += 1; } aisleFog.InitFog(calcRectPosition, calcRectSize); CurrWorld.FogMaskRoot.AddChild(aisleFog); roomDoorInfo.AisleFogMask = aisleFog; roomDoorInfo.ConnectDoor.AisleFogMask = aisleFog; //过道迷雾区域 var fogArea = new AisleFogArea(); fogArea.Init(roomDoorInfo, new Rect2I( fogAreaRect.Position * GameConfig.TileCellSize, fogAreaRect.Size * GameConfig.TileCellSize ) ); roomDoorInfo.AisleFogArea = fogArea; roomDoorInfo.ConnectDoor.AisleFogArea = fogArea; CurrWorld.AffiliationAreaRoot.AddChild(fogArea); } //预览迷雾区域 var previewRoomFog = new PreviewFogMask(); roomDoorInfo.PreviewRoomFogMask = previewRoomFog; previewRoomFog.Init(roomDoorInfo, PreviewFogMask.PreviewFogType.Room); previewRoomFog.SetActive(false); CurrWorld.FogMaskRoot.AddChild(previewRoomFog); var previewAisleFog = new PreviewFogMask(); roomDoorInfo.PreviewAisleFogMask = previewAisleFog; previewAisleFog.Init(roomDoorInfo, PreviewFogMask.PreviewFogType.Aisle); previewAisleFog.SetActive(false); CurrWorld.FogMaskRoot.AddChild(previewAisleFog); } } private void CreatePreviewSprite(RoomInfo roomInfo) { //房间区域 var sprite = new TextureRect(); //sprite.Centered = false; sprite.Texture = roomInfo.PreviewTexture; sprite.Position = roomInfo.Position + new Vector2I(1, 3); var material = ResourceManager.Load<ShaderMaterial>(ResourcePath.resource_material_Outline2_tres, false); material.SetShaderParameter("outline_color", new Color(1, 1, 1, 0.9f)); material.SetShaderParameter("scale", 0.5f); sprite.Material = material; roomInfo.PreviewSprite = sprite; //过道 if (roomInfo.Doors != null) { foreach (var doorInfo in roomInfo.Doors) { if (doorInfo.IsForward) { var aisleSprite = new TextureRect(); //aisleSprite.Centered = false; aisleSprite.Texture = doorInfo.AislePreviewTexture; //调整过道预览位置 if (doorInfo.Direction == DoorDirection.N || doorInfo.Direction == DoorDirection.S || doorInfo.ConnectDoor.Direction == DoorDirection.N || doorInfo.ConnectDoor.Direction == DoorDirection.S) { aisleSprite.Position = doorInfo.AisleFloorRect.Position + new Vector2I(0, 1); } else { aisleSprite.Position = doorInfo.AisleFloorRect.Position; } // var aisleSpriteMaterial = ResourceManager.Load<ShaderMaterial>(ResourcePath.resource_material_Outline2_tres, false); // aisleSpriteMaterial.SetShaderParameter("outline_color", new Color(1, 1, 1, 0.9f)); // aisleSpriteMaterial.SetShaderParameter("scale", 0.5f); // aisleSprite.Material = aisleSpriteMaterial; doorInfo.AislePreviewSprite = aisleSprite; doorInfo.ConnectDoor.AislePreviewSprite = aisleSprite; } } } } /// <summary> /// 玩家第一次进入某个房间回调 /// </summary> private void OnPlayerFirstEnterRoom(object o) { _checkEnemyTimer = 0; var room = (RoomInfo)o; room.OnFirstEnter(); //如果关门了, 那么房间外的敌人就会丢失目标 if (room.IsSeclusion) { var playerAffiliationArea = CurrWorld.Player.AffiliationArea; foreach (var role in CurrWorld.Role_InstanceList) { //不与玩家处于同一个房间 if (role is AiRole enemy && !enemy.IsDestroyed && enemy.AffiliationArea != playerAffiliationArea) { if (enemy.StateController.CurrState != AIStateEnum.AiNormal) { enemy.StateController.ChangeState(AIStateEnum.AiNormal); } } } } } /// <summary> /// 玩家进入某个房间回调 /// </summary> private void OnPlayerEnterRoom(object o) { var roomInfo = (RoomInfo)o; if (_affiliationAreaFlag != roomInfo.AffiliationArea) { if (!roomInfo.AffiliationArea.IsDestroyed) { //刷新迷雾 FogMaskHandler.RefreshRoomFog(roomInfo); } _affiliationAreaFlag = roomInfo.AffiliationArea; } } /// <summary> /// 检测当前房间敌人是否已经消灭干净, 应当每秒执行一次 /// </summary> private void OnCheckEnemy() { var activeRoom = ActiveRoomInfo; if (activeRoom != null && activeRoom.RoomPreinstall != null) { if (activeRoom.RoomPreinstall.IsRunWave) //正在生成标记 { if (activeRoom.RoomPreinstall.IsCurrWaveOver()) //所有标记执行完成 { //房间内是否有存活的敌人 var flag = ActiveAffiliationArea.ExistEnterItem( activityObject => activityObject is Role role && role.IsEnemyWithPlayer() ); //Debug.Log("当前房间存活数量: " + count); if (!flag) { activeRoom.OnClearRoom(); } } } } } private void DisposeRoomInfo(RoomInfo roomInfo) { roomInfo.Destroy(); } public override void _Draw() { if (ActivityObject.IsDebug) { StartRoomInfo?.EachRoom(info => { DrawRect(new Rect2(info.Waypoints * GameConfig.TileCellSize, new Vector2(16, 16)), Colors.Red); }); //绘制房间区域 if (_dungeonGenerator != null) { DrawRoomInfo(StartRoomInfo); } //绘制边缘线 } } //绘制房间区域, debug 用 private void DrawRoomInfo(RoomInfo roomInfo) { var cellSize = GameConfig.TileCellSize; var pos1 = (roomInfo.Position + roomInfo.Size / 2) * cellSize; //绘制下一个房间 foreach (var nextRoom in roomInfo.Next) { var pos2 = (nextRoom.Position + nextRoom.Size / 2) * cellSize; DrawLine(pos1, pos2, Colors.Red); DrawRoomInfo(nextRoom); } DrawString(ResourceManager.DefaultFont16Px, pos1 - new Vector2I(0, 10), "Id: " + roomInfo.Id.ToString()); DrawString(ResourceManager.DefaultFont16Px, pos1 + new Vector2I(0, 10), "Layer: " + roomInfo.Layer.ToString()); //绘制门 foreach (var roomDoor in roomInfo.Doors) { var originPos = roomDoor.OriginPosition * cellSize; switch (roomDoor.Direction) { case DoorDirection.E: DrawLine(originPos, originPos + new Vector2(3, 0) * cellSize, Colors.Yellow); DrawLine(originPos + new Vector2(0, 4) * cellSize, originPos + new Vector2(3, 4) * cellSize, Colors.Yellow); break; case DoorDirection.W: DrawLine(originPos, originPos - new Vector2(3, 0) * cellSize, Colors.Yellow); DrawLine(originPos + new Vector2(0, 4) * cellSize, originPos - new Vector2(3, -4) * cellSize, Colors.Yellow); break; case DoorDirection.S: DrawLine(originPos, originPos + new Vector2(0, 3) * cellSize, Colors.Yellow); DrawLine(originPos + new Vector2(4, 0) * cellSize, originPos + new Vector2(4, 3) * cellSize, Colors.Yellow); break; case DoorDirection.N: DrawLine(originPos, originPos - new Vector2(0, 3) * cellSize, Colors.Yellow); DrawLine(originPos + new Vector2(4, 0) * cellSize, originPos - new Vector2(-4, 3) * cellSize, Colors.Yellow); break; } //绘制房间区域 DrawRect(new Rect2(roomInfo.Position * cellSize, roomInfo.Size * cellSize), Colors.Blue, false); if (roomDoor.HasCross && roomDoor.RoomInfo.Id < roomDoor.ConnectRoom.Id) { DrawRect(new Rect2(roomDoor.Cross * cellSize, new Vector2(cellSize * 4, cellSize * 4)), Colors.Yellow, false); } } } /// <summary> /// 将房间类型枚举转为字符串 /// </summary> public static string DungeonRoomTypeToString(DungeonRoomType roomType) { switch (roomType) { case DungeonRoomType.Battle: return "battle"; case DungeonRoomType.Inlet: return "inlet"; case DungeonRoomType.Outlet: return "outlet"; case DungeonRoomType.Boss: return "boss"; case DungeonRoomType.Reward: return "reward"; case DungeonRoomType.Shop: return "shop"; case DungeonRoomType.Event: return "event"; } return "battle"; } /// <summary> /// 将房间类型枚举转为描述字符串 /// </summary> public static string DungeonRoomTypeToDescribeString(DungeonRoomType roomType) { switch (roomType) { case DungeonRoomType.Battle: return "战斗房间"; case DungeonRoomType.Inlet: return "起始房间"; case DungeonRoomType.Outlet: return "结束房间"; case DungeonRoomType.Boss: return "Boss房间"; case DungeonRoomType.Reward: return "奖励房间"; case DungeonRoomType.Shop: return "商店房间"; case DungeonRoomType.Event: return "事件房间"; } return "战斗房间"; } /// <summary> /// 检测地牢是否可以执行生成 /// </summary> /// <param name="groupName">组名称</param> public static DungeonCheckState CheckDungeon(string groupName) { if (GameApplication.Instance.RoomConfig.TryGetValue(groupName, out var group)) { //验证该组是否满足生成地牢的条件 if (group.InletList.Count == 0) { return new DungeonCheckState(true, "当没有可用的起始房间!"); } else if (group.OutletList.Count == 0) { return new DungeonCheckState(true, "没有可用的结束房间!"); } else if (group.BattleList.Count == 0) { return new DungeonCheckState(true, "没有可用的战斗房间!"); } return new DungeonCheckState(false, null); } return new DungeonCheckState(true, "未找到地牢组"); } }