diff --git a/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs b/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs index e627e82..e056bbf 100644 --- a/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs +++ b/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs @@ -4,7 +4,7 @@ using Godot; /// -/// 归属区域 +/// 房间归属区域 /// public partial class AffiliationArea : Area2D, IDestroy { @@ -89,7 +89,7 @@ //如果是玩家 if (activityObject == Player.Current) { - OnPlayerEnterRoom(); + OnPlayerInsertRoom(); } } @@ -251,7 +251,7 @@ } //玩家进入房间 - private void OnPlayerEnterRoom() + private void OnPlayerInsertRoom() { if (IsFirstEnterFlag) { diff --git a/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs b/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs index ba37303..8dcc1a8 100644 --- a/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs +++ b/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs @@ -560,6 +560,7 @@ var roomDoor = new RoomDoorInfo(); var nextRoomDoor = new RoomDoorInfo(); roomDoor.RoomInfo = roomInfo; + roomDoor.IsForward = true; nextRoomDoor.RoomInfo = nextRoomInfo; roomDoor.ConnectRoom = nextRoomInfo; roomDoor.ConnectDoor = nextRoomDoor; diff --git a/DungeonShooting_Godot/src/framework/map/fog/AisleFogArea.cs b/DungeonShooting_Godot/src/framework/map/fog/AisleFogArea.cs new file mode 100644 index 0000000..f52c690 --- /dev/null +++ b/DungeonShooting_Godot/src/framework/map/fog/AisleFogArea.cs @@ -0,0 +1,93 @@ + +using Godot; + +/// +/// 过道迷雾区域碰撞器, 用于检测玩家是否进入过道 +/// +public partial class AisleFogArea : Area2D, IDestroy +{ + public bool IsDestroyed { get; private set; } + + /// + /// 所属连接的门 (起始门) + /// + public RoomDoorInfo RoomDoorInfo { get; private set; } + + private bool _init = false; + private RectangleShape2D _shape; + + /// + /// 根据矩形区域初始化归属区域 + /// + public void Init(RoomDoorInfo doorInfo, Rect2I rect2) + { + if (_init) + { + return; + } + + _init = true; + + RoomDoorInfo = doorInfo; + var collisionShape = new CollisionShape2D(); + collisionShape.GlobalPosition = rect2.Position + rect2.Size / 2; + var shape = new RectangleShape2D(); + _shape = shape; + shape.Size = rect2.Size; + collisionShape.Shape = shape; + AddChild(collisionShape); + _Init(); + } + + private void _Init() + { + Monitoring = true; + Monitorable = false; + CollisionLayer = PhysicsLayer.None; + CollisionMask = PhysicsLayer.Player; + + BodyEntered += OnBodyEntered; + //BodyExited += OnBodyExited; + } + + public void Destroy() + { + if (IsDestroyed) + { + return; + } + + IsDestroyed = true; + QueueFree(); + } + + private void OnBodyEntered(Node2D body) + { + if (body == Player.Current) + { + //注意需要延时调用 + CallDeferred(nameof(InsertItem)); + } + } + + // private void OnBodyExited(Node2D body) + // { + // if (body == Player.Current) + // { + // //注意需要延时调用 + // CallDeferred(nameof(LeavePlayer)); + // } + // } + + private void InsertItem() + { + //GD.Print("玩家进入过道"); + RoomDoorInfo.ClearFog(); + } + + // private void LeavePlayer() + // { + // //GD.Print("玩家离开过道"); + // //RoomDoorInfo.DarkFog(); + // } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/map/fog/FogMask.cs b/DungeonShooting_Godot/src/framework/map/fog/FogMask.cs index 40758cb..b80dc10 100644 --- a/DungeonShooting_Godot/src/framework/map/fog/FogMask.cs +++ b/DungeonShooting_Godot/src/framework/map/fog/FogMask.cs @@ -1,4 +1,6 @@  +using System; +using System.Collections; using Godot; /// @@ -29,6 +31,7 @@ private static bool _initSprite = false; + private long _cid = -1; private static void InitSprite() { if (_initSprite) @@ -105,9 +108,26 @@ /// 过渡时间 public void TransitionAlpha(float targetAlpha, float time) { - var tween = CreateTween(); - tween.TweenProperty(this, "color", new Color(1, 1, 1, targetAlpha), time); - tween.Play(); + if (_cid >= 0) + { + World.Current.StopCoroutine(_cid); + } + + _cid = World.Current.StartCoroutine(RunTransitionAlpha(targetAlpha, time)); + } + + private IEnumerator RunTransitionAlpha(float targetAlpha, float time) + { + var originColor = Color; + var a = originColor.A; + var delta = Mathf.Abs(a - targetAlpha) / time; + while (Math.Abs(a - targetAlpha) > 0.001f) + { + a = Mathf.MoveToward(a, targetAlpha, delta * (float)World.Current.GetProcessDeltaTime()); + Color = new Color(1, 1, 1, a); + yield return null; + } + _cid = -1; } public void Destroy() diff --git a/DungeonShooting_Godot/src/framework/map/room/RoomDoorInfo.cs b/DungeonShooting_Godot/src/framework/map/room/RoomDoorInfo.cs index 58365e0..ebe9183 100644 --- a/DungeonShooting_Godot/src/framework/map/room/RoomDoorInfo.cs +++ b/DungeonShooting_Godot/src/framework/map/room/RoomDoorInfo.cs @@ -8,13 +8,18 @@ public class RoomDoorInfo : IDestroy { public bool IsDestroyed { get; private set; } - + /// /// 所在墙面方向 /// public DoorDirection Direction; /// + /// 是否是正向的门 + /// + public bool IsForward; + + /// /// 所在的房间 /// public RoomInfo RoomInfo; @@ -60,6 +65,16 @@ public FogMask FogMask; /// + /// 过道迷雾区域 + /// + public AisleFogArea AisleFogArea; + + /// + /// 当前门连接的过道是否探索过 + /// + public bool IsExplored { get; private set; } = false; + + /// /// 世界坐标下的原点坐标, 单位: 像素 /// public Vector2I GetWorldOriginPosition() @@ -221,5 +236,36 @@ { FogMask.Destroy(); } + + if (AisleFogArea != null) + { + AisleFogArea.Destroy(); + } + } + + /// + /// 清除过道迷雾 + /// + public void ClearFog() + { + IsExplored = true; + ConnectDoor.IsExplored = true; + if (FogMask != null && Math.Abs(FogMask.Color.A - 1f) > 0.001f) + { + FogMask.TransitionAlpha(1, 0.3f); + } + } + + /// + /// 将过道迷雾变暗 + /// + public void DarkFog() + { + IsExplored = true; + ConnectDoor.IsExplored = true; + if (FogMask != null && Math.Abs(FogMask.Color.A - GameConfig.DarkFogAlpha) > 0.001f) + { + FogMask.TransitionAlpha(GameConfig.DarkFogAlpha, 0.3f); + } } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/map/room/RoomInfo.cs b/DungeonShooting_Godot/src/framework/map/room/RoomInfo.cs index 5d0c04e..fe7f2f7 100644 --- a/DungeonShooting_Godot/src/framework/map/room/RoomInfo.cs +++ b/DungeonShooting_Godot/src/framework/map/room/RoomInfo.cs @@ -1,4 +1,5 @@ +using System; using System.Collections.Generic; using Godot; @@ -329,12 +330,6 @@ return; } - //清除迷雾 - if (FogMask != null && FogMask.Color.A < 1) - { - FogMask.TransitionAlpha(1, 0.3f); - } - //房间内有敌人, 或者会刷新敌人才会关门 var hasEnemy = false; if (AffiliationArea.ExistEnterItem(activityObject => activityObject.CollisionWithMask(PhysicsLayer.Enemy))) //先判断房间里面是否有敌人 @@ -398,17 +393,14 @@ foreach (var doorInfo in Doors) { doorInfo.Door.OpenDoor(); - } - - //清除过道的迷雾 - foreach (var roomDoorInfo in GetForwardDoors()) - { - if (roomDoorInfo.FogMask != null && roomDoorInfo.FogMask.Color.A < 1) + + //过道迷雾 + doorInfo.AisleFogArea.Monitoring = true; + if (doorInfo.IsExplored) { - roomDoorInfo.FogMask.TransitionAlpha(1, 0.3f); + doorInfo.ClearFog(); } } - } /// @@ -425,18 +417,26 @@ foreach (var doorInfo in Doors) { doorInfo.Door.CloseDoor(); + + //过道迷雾 + doorInfo.AisleFogArea.Monitoring = false; + if (doorInfo.IsExplored) + { + doorInfo.DarkFog(); + } } } /// - /// 获取该房间所有正向的门,nextRoom.id > this.id + /// 获取该房间所有正向的门 /// public RoomDoorInfo[] GetForwardDoors() { var temp = new List(); foreach (var doorInfo in Doors) { - if (doorInfo.ConnectRoom.Id > Id) + if (doorInfo.IsForward) + //if (doorInfo.ConnectRoom.Id > Id) { temp.Add(doorInfo); } @@ -444,4 +444,26 @@ return temp.ToArray(); } + + /// + /// 清除迷雾 + /// + public void ClearFog() + { + if (FogMask != null && Math.Abs(FogMask.Color.A - 1) > 0.001f) + { + FogMask.TransitionAlpha(1, 0.3f); + } + } + + /// + /// 将迷雾变暗 + /// + public void DarkFog() + { + if (FogMask != null && Math.Abs(FogMask.Color.A - GameConfig.DarkFogAlpha) > 0.001f) + { + FogMask.TransitionAlpha(GameConfig.DarkFogAlpha, 0.3f); + } + } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/GameConfig.cs b/DungeonShooting_Godot/src/game/GameConfig.cs index 756b76b..046c27a 100644 --- a/DungeonShooting_Godot/src/game/GameConfig.cs +++ b/DungeonShooting_Godot/src/game/GameConfig.cs @@ -77,4 +77,9 @@ /// 预览图大小 /// public const int PreviewImageSize = 196; + + /// + /// 变暗迷雾的透明度值 + /// + public const float DarkFogAlpha = 0.2f; } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/room/DungeonManager.cs b/DungeonShooting_Godot/src/game/room/DungeonManager.cs index 20d3ab6..5801dfc 100644 --- a/DungeonShooting_Godot/src/game/room/DungeonManager.cs +++ b/DungeonShooting_Godot/src/game/room/DungeonManager.cs @@ -57,6 +57,8 @@ //用于检查房间敌人的计时器 private float _checkEnemyTimer = 0; + //用于记录玩家上一个所在区域 + private AffiliationArea _affiliationAreaFlag; public DungeonManager() @@ -450,9 +452,12 @@ //生成通道迷雾 foreach (var roomDoorInfo in roomDoorInfos) { + Rect2I calcRect; + Rect2I fogAreaRect; if (!roomDoorInfo.HasCross) { - var calcRect = roomDoorInfo.GetAisleRect(); + calcRect = roomDoorInfo.GetAisleRect(); + fogAreaRect = calcRect; if (roomDoorInfo.Direction == DoorDirection.E || roomDoorInfo.Direction == DoorDirection.W) { calcRect.Position += new Vector2I(2, 0); @@ -463,61 +468,64 @@ calcRect.Position += new Vector2I(0, 2); calcRect.Size -= new Vector2I(0, 4); } - var aisleFog = new FogMask(); - aisleFog.BlendMode = Light2D.BlendModeEnum.Mix; - aisleFog.InitFog(calcRect.Position, calcRect.Size, alpha); - World.FogMaskRoot.AddChild(aisleFog); - roomDoorInfo.FogMask = aisleFog; - roomDoorInfo.ConnectDoor.FogMask = aisleFog; } else { var aisleRect = roomDoorInfo.GetCrossAisleRect(); - var calcAisleRect = aisleRect.CalcAisleRect(); + calcRect = aisleRect.CalcAisleRect(); + fogAreaRect = calcRect; switch (roomDoorInfo.Direction) { case DoorDirection.E: - calcAisleRect.Position += new Vector2I(2, 0); - calcAisleRect.Size -= new Vector2I(2, 0); + calcRect.Position += new Vector2I(2, 0); + calcRect.Size -= new Vector2I(2, 0); break; case DoorDirection.W: - calcAisleRect.Size -= new Vector2I(2, 0); + calcRect.Size -= new Vector2I(2, 0); break; case DoorDirection.S: - calcAisleRect.Position += new Vector2I(0, 2); - calcAisleRect.Size -= new Vector2I(0, 2); + calcRect.Position += new Vector2I(0, 2); + calcRect.Size -= new Vector2I(0, 2); break; case DoorDirection.N: - calcAisleRect.Size -= new Vector2I(0, 2); + calcRect.Size -= new Vector2I(0, 2); break; } switch (roomDoorInfo.ConnectDoor.Direction) { case DoorDirection.E: - calcAisleRect.Position += new Vector2I(2, 0); - calcAisleRect.Size -= new Vector2I(2, 0); + calcRect.Position += new Vector2I(2, 0); + calcRect.Size -= new Vector2I(2, 0); break; case DoorDirection.W: - calcAisleRect.Size -= new Vector2I(2, 0); + calcRect.Size -= new Vector2I(2, 0); break; case DoorDirection.S: - calcAisleRect.Position += new Vector2I(0, 2); - calcAisleRect.Size -= new Vector2I(0, 2); + calcRect.Position += new Vector2I(0, 2); + calcRect.Size -= new Vector2I(0, 2); break; case DoorDirection.N: - calcAisleRect.Size -= new Vector2I(0, 2); + calcRect.Size -= new Vector2I(0, 2); break; } - - var aisleFog = new FogMask(); - aisleFog.BlendMode = Light2D.BlendModeEnum.Mix; - aisleFog.InitFog(calcAisleRect.Position, calcAisleRect.Size, alpha); - World.FogMaskRoot.AddChild(aisleFog); - roomDoorInfo.FogMask = aisleFog; - roomDoorInfo.ConnectDoor.FogMask = aisleFog; } + + //过道迷雾遮罩 + var aisleFog = new FogMask(); + aisleFog.BlendMode = Light2D.BlendModeEnum.Mix; + aisleFog.InitFog(calcRect.Position, calcRect.Size); + World.FogMaskRoot.AddChild(aisleFog); + roomDoorInfo.FogMask = aisleFog; + roomDoorInfo.ConnectDoor.FogMask = 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; + World.AffiliationAreaRoot.AddChild(fogArea); } } @@ -551,6 +559,26 @@ /// private void OnPlayerEnterRoom(object o) { + var roomInfo = (RoomInfo)o; + if (_affiliationAreaFlag != roomInfo.AffiliationArea) + { + if (_affiliationAreaFlag != null) + { + if (!_affiliationAreaFlag.IsDestroyed) + { + //上一个房间变暗 + _affiliationAreaFlag.RoomInfo.DarkFog(); + } + } + + if (!roomInfo.AffiliationArea.IsDestroyed) + { + //当前房间变亮 + roomInfo.ClearFog(); + } + + _affiliationAreaFlag = roomInfo.AffiliationArea; + } } /// diff --git a/DungeonShooting_Godot/src/game/room/World.cs b/DungeonShooting_Godot/src/game/room/World.cs index 159ba87..00ca2eb 100644 --- a/DungeonShooting_Godot/src/game/room/World.cs +++ b/DungeonShooting_Godot/src/game/room/World.cs @@ -8,6 +8,11 @@ public partial class World : CanvasModulate, ICoroutine { /// + /// 当前的游戏世界对象 + /// + public static World Current => GameApplication.Instance.World; + + /// /// //对象根节点 /// [Export] public Node2D NormalLayer;