diff --git a/DungeonShooting_Godot/prefab/map/RoomDoor.tscn b/DungeonShooting_Godot/prefab/map/RoomDoor.tscn index 6f28778..a45d0e3 100644 --- a/DungeonShooting_Godot/prefab/map/RoomDoor.tscn +++ b/DungeonShooting_Godot/prefab/map/RoomDoor.tscn @@ -41,10 +41,10 @@ [node name="AnimatedSprite" type="AnimatedSprite2D" parent="."] material = SubResource("ShaderMaterial_f8vun") -position = Vector2(0, -8) +position = Vector2(0, -16) scale = Vector2(0.5, 0.25) sprite_frames = SubResource("SpriteFrames_ugstb") [node name="Collision" type="CollisionShape2D" parent="."] -position = Vector2(0, -8) +position = Vector2(0, -16) shape = SubResource("RectangleShape2D_xgcls") diff --git a/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs b/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs index 95c820e..a38d89f 100644 --- a/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs +++ b/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs @@ -17,10 +17,13 @@ /// 当前归属区域包含的所有物体对象 /// private readonly HashSet _includeItems = new HashSet(); - + + /// + /// 玩家是否是第一次进入 + /// + public bool IsFirstEnterFlag { get; private set; } = true; + private bool _init = false; - //玩家是否是第一次进入 - private bool _isFirstEnterFlag = true; /// /// 根据矩形区域初始化归属区域 @@ -124,10 +127,10 @@ //玩家进入房间 private void OnPlayerEnterRoom() { - if (_isFirstEnterFlag) + if (IsFirstEnterFlag) { EventManager.EmitEvent(EventEnum.OnPlayerFirstEnterRoom, RoomInfo); - _isFirstEnterFlag = false; + IsFirstEnterFlag = false; } EventManager.EmitEvent(EventEnum.OnPlayerEnterRoom, RoomInfo); } diff --git a/DungeonShooting_Godot/src/framework/map/DungeonTile.cs b/DungeonShooting_Godot/src/framework/map/DungeonTile.cs index b0d7553..9367ea4 100644 --- a/DungeonShooting_Godot/src/framework/map/DungeonTile.cs +++ b/DungeonShooting_Godot/src/framework/map/DungeonTile.cs @@ -435,6 +435,7 @@ } } + //横向过道 private void FullHorizontalAisle(AutoTileConfig config, Rect2 rect) { FillRect(AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(0, 1), rect.Size - new Vector2(0, 2)); @@ -442,6 +443,7 @@ FillRect(TopMapLayer, config.B, rect.Position + new Vector2(0, rect.Size.Y - 1), new Vector2(rect.Size.X, 1)); } + //纵向过道 private void FullVerticalAisle(AutoTileConfig config, Rect2 rect) { FillRect(AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(1, 0), rect.Size - new Vector2(2, 0)); diff --git a/DungeonShooting_Godot/src/framework/map/RoomInfo.cs b/DungeonShooting_Godot/src/framework/map/RoomInfo.cs index 1d45115..ff2f39c 100644 --- a/DungeonShooting_Godot/src/framework/map/RoomInfo.cs +++ b/DungeonShooting_Godot/src/framework/map/RoomInfo.cs @@ -57,6 +57,11 @@ /// 当前房间归属区域 /// public AffiliationArea Affiliation; + + /// + /// 是否处于闭关状态, 也就是房间门没有打开 + /// + public bool IsSeclusion { get; private set; } = false; /// /// 获取房间的全局坐标, 单位: 像素 @@ -109,4 +114,35 @@ { return Position.Y; } + + /// + /// 房间准备好了, 准备刷敌人, 并且关闭所有门 + /// + public void BeReady() + { + IsSeclusion = true; + //关门 + foreach (var doorInfo in Doors) + { + doorInfo.Door.CloseDoor(); + } + //根据标记生成对象 + foreach (var mark in ActivityMarks) + { + mark.BeReady(this); + } + } + + /// + /// 当前房间所有敌人都被清除了 + /// + public void OnClearRoom() + { + IsSeclusion = false; + //开门 + foreach (var doorInfo in Doors) + { + doorInfo.Door.OpenDoor(); + } + } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/map/mark/ActivityMark.cs b/DungeonShooting_Godot/src/framework/map/mark/ActivityMark.cs index f0aab24..428ee82 100644 --- a/DungeonShooting_Godot/src/framework/map/mark/ActivityMark.cs +++ b/DungeonShooting_Godot/src/framework/map/mark/ActivityMark.cs @@ -42,7 +42,7 @@ var id = GetItemId(); var instance = ActivityObject.Create(id); instance.PutDown(GlobalPosition, Layer); - QueueFree(); + Visible = false; } public override void _Draw() diff --git a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs index 3c66f88..76f4be1 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs @@ -178,17 +178,91 @@ /// public bool CheckUsableWeaponInUnclaimed() { - //如果存在有子弹的武器 foreach (var unclaimedWeapon in Weapon.UnclaimedWeapons) { - if (!unclaimedWeapon.IsTotalAmmoEmpty() && !unclaimedWeapon.HasSign(SignNames.AiFindWeaponSign)) + //判断是否能拾起武器, 条件: 相同的房间 + if (unclaimedWeapon.Affiliation == Affiliation) { - return true; + if (!unclaimedWeapon.IsTotalAmmoEmpty()) + { + if (!unclaimedWeapon.HasSign(SignNames.AiFindWeaponSign)) + { + return true; + } + else + { + //判断是否可以移除该标记 + var enemy = unclaimedWeapon.GetSign(SignNames.AiFindWeaponSign); + if (enemy == null || enemy.IsDestroyed) //标记当前武器的敌人已经被销毁 + { + unclaimedWeapon.RemoveSign(SignNames.AiFindWeaponSign); + return true; + } + else if (!enemy.IsAllWeaponTotalAmmoEmpty()) //标记当前武器的敌人已经有新的武器了 + { + unclaimedWeapon.RemoveSign(SignNames.AiFindWeaponSign); + return true; + } + } + } } } return false; } + + /// + /// 寻找可用的武器 + /// + public Weapon FindTargetWeapon() + { + Weapon target = null; + var position = Position; + foreach (var weapon in Weapon.UnclaimedWeapons) + { + //判断是否能拾起武器, 条件: 相同的房间, 或者当前房间目前没有战斗, 或者不在战斗房间 + if (weapon.Affiliation == Affiliation) + { + //还有弹药 + if (!weapon.IsTotalAmmoEmpty()) + { + //查询是否有其他敌人标记要拾起该武器 + if (weapon.HasSign(SignNames.AiFindWeaponSign)) + { + var enemy = weapon.GetSign(SignNames.AiFindWeaponSign); + if (enemy == this) //就是自己标记的 + { + + } + else if (enemy == null || enemy.IsDestroyed) //标记当前武器的敌人已经被销毁 + { + weapon.RemoveSign(SignNames.AiFindWeaponSign); + } + else if (!enemy.IsAllWeaponTotalAmmoEmpty()) //标记当前武器的敌人已经有新的武器了 + { + weapon.RemoveSign(SignNames.AiFindWeaponSign); + } + else //放弃这把武器 + { + continue; + } + } + + if (target == null) //第一把武器 + { + target = weapon; + } + else if (target.Position.DistanceSquaredTo(position) > + weapon.Position.DistanceSquaredTo(position)) //距离更近 + { + target = weapon; + } + } + } + } + + return target; + } /// /// 检查是否能切换到 AiStateEnum.AiLeaveFor 状态 diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs index f36931b..bc00378 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs @@ -2,7 +2,7 @@ using Godot; /// -/// Ai 寻找弹药 +/// Ai 寻找弹药, 进入该状态需要在参数中传入目标武器对象 /// public class AiFindAmmoState : StateBase { @@ -22,17 +22,18 @@ public override void Enter(AiStateEnum prev, params object[] args) { - _navigationUpdateTimer = 0; - _isInTailAfterRange = false; - _tailAfterTimer = 0; - //找到能用的武器 - FindTargetWeapon(); - if (_target == null) + if (args.Length == 0) { + GD.PrintErr("进入 AiStateEnum.AiFindAmmo 状态必须要把目标武器当成参数传过来"); ChangeStateLate(prev); return; } + SetTargetWeapon((Weapon)args[0]); + _navigationUpdateTimer = 0; + _isInTailAfterRange = false; + _tailAfterTimer = 0; + //标记武器 _target.SetSign(SignNames.AiFindWeaponSign, Master); } @@ -62,10 +63,10 @@ //枪口指向玩家 Master.LookTargetPosition(playerPos); - if (_target.IsQueuedForDeletion() || _target.IsTotalAmmoEmpty()) //已经被销毁, 或者弹药已经被其他角色捡走 + if (_target.IsDestroyed || _target.IsTotalAmmoEmpty()) //已经被销毁, 或者弹药已经被其他角色捡走 { //再去寻找其他武器 - FindTargetWeapon(); + SetTargetWeapon(Master.FindTargetWeapon()); if (_target == null) //也没有其他可用的武器了 { @@ -79,7 +80,7 @@ else if (_target.Master != null) //武器已经被其他角色拾起! { //再去寻找其他武器 - FindTargetWeapon(); + SetTargetWeapon(Master.FindTargetWeapon()); if (_target == null) //也没有其他可用的武器了 { @@ -120,6 +121,16 @@ { return _tailAfterTimer > 10 ? AiStateEnum.AiNormal : AiStateEnum.AiTailAfter; } + + private void SetTargetWeapon(Weapon weapon) + { + _target = weapon; + //设置目标点 + if (_target != null) + { + Master.NavigationAgent2D.TargetPosition = _target.GlobalPosition; + } + } public override void DebugDraw() { @@ -138,53 +149,4 @@ } } - - private void FindTargetWeapon() - { - _target = null; - var position = Master.Position; - foreach (var weapon in Weapon.UnclaimedWeapons) - { - if (!weapon.IsTotalAmmoEmpty()) - { - //查询是否有其他敌人标记要拾起该武器 - if (weapon.HasSign(SignNames.AiFindWeaponSign)) - { - var enemy = weapon.GetSign(SignNames.AiFindWeaponSign); - if (enemy == Master) //就是自己标记的 - { - - } - else if (enemy == null || enemy.IsQueuedForDeletion()) //标记当前武器的敌人已经被销毁 - { - weapon.RemoveSign(SignNames.AiFindWeaponSign); - } - else if (!enemy.IsAllWeaponTotalAmmoEmpty()) //标记当前武器的敌人已经有新的武器了 - { - weapon.RemoveSign(SignNames.AiFindWeaponSign); - } - else //放弃这把武器 - { - continue; - } - } - - if (_target == null) //第一把武器 - { - _target = weapon; - } - else if (_target.Position.DistanceSquaredTo(position) > - weapon.Position.DistanceSquaredTo(position)) //距离更近 - { - _target = weapon; - } - } - } - - //设置目标点 - if (_target != null) - { - Master.NavigationAgent2D.TargetPosition = _target.GlobalPosition; - } - } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiFollowUpState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiFollowUpState.cs index c3082d3..fd6850a 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/state/AiFollowUpState.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiFollowUpState.cs @@ -32,10 +32,10 @@ if (Master.IsAllWeaponTotalAmmoEmpty()) { //再寻找是否有可用的武器 - if (Master.CheckUsableWeaponInUnclaimed()) + var targetWeapon = Master.FindTargetWeapon(); + if (targetWeapon != null) { - //切换到寻找武器状态 - ChangeStateLate(AiStateEnum.AiFindAmmo); + ChangeStateLate(AiStateEnum.AiFindAmmo, targetWeapon); return; } else @@ -44,7 +44,7 @@ ChangeStateLate(AiStateEnum.AiSurround); } } - + var playerPos = Player.Current.GetCenterPosition(); //更新玩家位置 diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiLeaveForState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiLeaveForState.cs index 80766a7..7823d03 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/state/AiLeaveForState.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiLeaveForState.cs @@ -25,15 +25,15 @@ ChangeStateLate(prev); return; } - + //先检查弹药是否打光 if (Master.IsAllWeaponTotalAmmoEmpty()) { //再寻找是否有可用的武器 - if (Master.CheckUsableWeaponInUnclaimed()) + var targetWeapon = Master.FindTargetWeapon(); + if (targetWeapon != null) { - //切换到寻找武器状态 - ChangeStateLate(AiStateEnum.AiFindAmmo); + ChangeStateLate(AiStateEnum.AiFindAmmo, targetWeapon); } } } diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiSurroundState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiSurroundState.cs index 12c4629..64a42f6 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/state/AiSurroundState.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiSurroundState.cs @@ -44,14 +44,14 @@ if (Master.IsAllWeaponTotalAmmoEmpty()) { //再寻找是否有可用的武器 - if (Master.CheckUsableWeaponInUnclaimed()) + var targetWeapon = Master.FindTargetWeapon(); + if (targetWeapon != null) { - //切换到寻找武器状态 - ChangeStateLate(AiStateEnum.AiFindAmmo); + ChangeStateLate(AiStateEnum.AiFindAmmo, targetWeapon); return; } } - + var playerPos = Player.Current.GetCenterPosition(); var weapon = Master.Holster.ActiveWeapon; diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs index 8d3d507..f965f41 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs @@ -32,10 +32,10 @@ if (Master.IsAllWeaponTotalAmmoEmpty()) { //再寻找是否有可用的武器 - if (Master.CheckUsableWeaponInUnclaimed()) + var targetWeapon = Master.FindTargetWeapon(); + if (targetWeapon != null) { - //切换到寻找武器状态 - ChangeStateLate(AiStateEnum.AiFindAmmo); + ChangeStateLate(AiStateEnum.AiFindAmmo, targetWeapon); } } } diff --git a/DungeonShooting_Godot/src/game/room/RoomDoor.cs b/DungeonShooting_Godot/src/game/room/RoomDoor.cs index 3e2878a..0df20d9 100644 --- a/DungeonShooting_Godot/src/game/room/RoomDoor.cs +++ b/DungeonShooting_Godot/src/game/room/RoomDoor.cs @@ -10,6 +10,11 @@ /// public DoorDirection Direction => _door.Direction; + /// + /// 门是否关闭 + /// + public bool IsClose { get; private set; } + private RoomDoorInfo _door; /// @@ -42,6 +47,7 @@ /// public void OpenDoor() { + IsClose = false; Visible = false; Collision.Disabled = true; _door.Navigation.NavigationNode.Enabled = true; @@ -52,6 +58,7 @@ /// public void CloseDoor() { + IsClose = true; Visible = true; Collision.Disabled = false; _door.Navigation.NavigationNode.Enabled = false; diff --git a/DungeonShooting_Godot/src/game/room/RoomManager.cs b/DungeonShooting_Godot/src/game/room/RoomManager.cs index 6fdfc29..4b5dff2 100644 --- a/DungeonShooting_Godot/src/game/room/RoomManager.cs +++ b/DungeonShooting_Godot/src/game/room/RoomManager.cs @@ -26,6 +26,16 @@ /// 玩家对象 /// public Player Player { get; private set; } + + /// + /// 当前玩家所在的房间 + /// + public RoomInfo ActiveRoom => Player?.Affiliation.RoomInfo; + + /// + /// 当前玩家所在的区域 + /// + public AffiliationArea ActiveAffiliation => Player?.Affiliation; private DungeonTile _dungeonTile; private AutoTileConfig _autoTileConfig; @@ -148,12 +158,6 @@ //创建房间归属区域 CreateRoomAisleAffiliation(roomInfo); - - //创建敌人 - // foreach (var roomInfoActivityMark in roomInfo.ActivityMarks) - // { - // roomInfoActivityMark.BeReady(roomInfo); - // } } //挂载房间导航区域 @@ -226,8 +230,8 @@ var affiliation = new AffiliationArea(); affiliation.Name = "AffiliationArea" + (_affiliationIndex++); affiliation.Init(roomInfo, new Rect2( - roomInfo.GetWorldPosition() + new Vector2(GenerateDungeon.TileCellSize * 1.5f, GenerateDungeon.TileCellSize * 1.5f), - (roomInfo.Size - new Vector2I(3, 3)) * GenerateDungeon.TileCellSize)); + roomInfo.GetWorldPosition() + new Vector2(GenerateDungeon.TileCellSize, GenerateDungeon.TileCellSize), + (roomInfo.Size - new Vector2I(2, 2)) * GenerateDungeon.TileCellSize)); roomInfo.Affiliation = affiliation; TileRoot.AddChild(affiliation); @@ -239,16 +243,7 @@ private void OnPlayerFirstEnterRoom(object o) { var room = (RoomInfo)o; - //关门 - foreach (var doorInfo in room.Doors) - { - doorInfo.Door.CloseDoor(); - } - //根据标记生成对象 - foreach (var mark in room.ActivityMarks) - { - mark.BeReady(room); - } + room.BeReady(); } /// @@ -264,15 +259,12 @@ private void OnEnemyDie(object o) { var inst = (ActivityObject)o; - var count = Player.Affiliation.FindIncludeItemsCount( + var count = ActiveAffiliation.FindIncludeItemsCount( activityObject => activityObject != inst && activityObject.CollisionWithLayer(PhysicsLayer.Enemy) ); if (count == 0) { - foreach (var doorInfo in Player.Affiliation.RoomInfo.Doors) - { - doorInfo.Door.OpenDoor(); - } + ActiveRoom.OnClearRoom(); } }