diff --git a/DungeonShooting_Godot/prefab/role/template/AiTemplate.tscn b/DungeonShooting_Godot/prefab/role/template/AiTemplate.tscn index 3866ed8..b9cb23d 100644 --- a/DungeonShooting_Godot/prefab/role/template/AiTemplate.tscn +++ b/DungeonShooting_Godot/prefab/role/template/AiTemplate.tscn @@ -33,6 +33,9 @@ position = Vector2(0, -8) enabled = false +[node name="MeleeAttackArea" parent="MountPoint" index="0"] +visible = true + [node name="ViewArea" type="Area2D" parent="MountPoint" index="1"] collision_layer = 0 collision_mask = 16 diff --git a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preinstall.json b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preinstall.json index 155c178..0008db3 100644 --- a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preinstall.json +++ b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preinstall.json @@ -1 +1 @@ -[{"Name":"Preinstall1","Weight":100,"Remark":"","AutoFill":true,"WaveList":[[{"Position":{"X":-81,"Y":25},"Size":{"X":0,"Y":0},"SpecialMarkType":1,"DelayTime":0,"MarkList":[]},{"Position":{"X":21,"Y":31},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"enemy0001","Weight":100,"Attr":{"Face":"1","Weapon":"weapon0003","CurrAmmon":"12","ResidueAmmo":"12"},"Altitude":0,"VerticalSpeed":5.551115E-14}]},{"Position":{"X":110,"Y":37},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"enemy0001","Weight":100,"Attr":{"Face":"-1","Weapon":"weapon0002","CurrAmmon":"7","ResidueAmmo":"7"},"Altitude":0,"VerticalSpeed":5.551115E-14}]},{"Position":{"X":-54,"Y":20},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0001","Weight":100,"Attr":{"CurrAmmon":"30","ResidueAmmo":"210"},"Altitude":8,"VerticalSpeed":5.551115E-14}]}]]}] \ No newline at end of file +[{"Name":"Preinstall1","Weight":100,"Remark":"","AutoFill":true,"WaveList":[[{"Position":{"X":-81,"Y":25},"Size":{"X":0,"Y":0},"SpecialMarkType":1,"DelayTime":0,"MarkList":[]},{"Position":{"X":21,"Y":31},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"enemy0001","Weight":100,"Attr":{"Face":"1","Weapon":"weapon0003","CurrAmmon":"12","ResidueAmmo":"12"},"Altitude":0,"VerticalSpeed":5.551115E-14}]},{"Position":{"X":-54,"Y":20},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0001","Weight":100,"Attr":{"CurrAmmon":"30","ResidueAmmo":"210"},"Altitude":8,"VerticalSpeed":5.551115E-14}]},{"Position":{"X":105,"Y":31},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"enemy0001","Weight":100,"Attr":{"Face":"0","Weapon":"weapon0003","CurrAmmon":"12","ResidueAmmo":"12"},"Altitude":0,"VerticalSpeed":0}]}]]}] \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs b/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs index b439592..4111d82 100644 --- a/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs +++ b/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs @@ -285,14 +285,14 @@ if (errorCode == GenerateRoomErrorCode.OutArea) { _failCount++; - Debug.Log("超出区域失败次数: " + _failCount); + //Debug.Log("超出区域失败次数: " + _failCount); if (_failCount >= _maxFailCount) { //_enableLimitRange = false; _failCount = 0; _rangeX += 50; _rangeY += 50; - Debug.Log("生成房间失败次数过多, 增大区域"); + //Debug.Log("生成房间失败次数过多, 增大区域"); } } diff --git a/DungeonShooting_Godot/src/game/GameApplication.cs b/DungeonShooting_Godot/src/game/GameApplication.cs index 53a5b93..0c2112e 100644 --- a/DungeonShooting_Godot/src/game/GameApplication.cs +++ b/DungeonShooting_Godot/src/game/GameApplication.cs @@ -134,7 +134,7 @@ //固定帧率 //Engine.MaxFps = TargetFps; //调试绘制开关 - ActivityObject.IsDebug = true; + ActivityObject.IsDebug = false; //Engine.TimeScale = 0.2f; //调整窗口分辨率 OnWindowSizeChanged(); diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs b/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs index 2935087..e782e18 100644 --- a/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs +++ b/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs @@ -9,9 +9,19 @@ public abstract partial class AiRole : Role { /// - /// 目标是否在视野内 + /// 目标是否在视野内, 视野内不能有墙壁遮挡 /// - public bool TargetInView { get; set; } = true; + public bool TargetInView { get; private set; } = false; + + /// + /// 目标间是否有墙壁遮挡 + /// + public bool TargetHasOcclusion { get; private set; } = false; + + /// + /// 目标是否在视野范围内, 不会考虑是否被枪遮挡 + /// + public bool TargetInViewRange { get; private set; } = false; /// /// 敌人身上的状态机控制器 @@ -79,26 +89,26 @@ { if (_viewRange != value) { - _viewRange = value; if (ViewAreaCollision != null) { - ViewAreaCollision.Polygon = Utils.CreateSectorPolygon(0, _viewRange, 120, 4); + ViewAreaCollision.Polygon = Utils.CreateSectorPolygon(0, value, 120, 4); } } + _viewRange = value; } } private float _viewRange = -1; /// + /// 默认视野半径 + /// + public float DefaultViewRange { get; set; } = 250; + + /// /// 发现玩家后跟随玩家的视野半径 /// public float TailAfterViewRange { get; set; } = 400; - - /// - /// 背后的视野半径, 单位像素 - /// - public float BackViewRange { get; set; } = 50; /// /// 攻击间隔时间, 秒 @@ -118,7 +128,7 @@ /// /// 临时存储攻击目标, 获取该值请调用 GetAttackTarget() 函数 /// - private Role AttackTarget { get; set; } = null; + private Role _attackTarget = null; private HashSet _viewTargets = new HashSet(); @@ -147,7 +157,40 @@ //NavigationAgent2D.VelocityComputed += OnVelocityComputed; } - + + protected override void Process(float delta) + { + base.Process(delta); + + if (LookTarget != null) + { + if (LookTarget.IsDestroyed) + { + LookTarget = null; + TargetInViewRange = false; + TargetHasOcclusion = false; + TargetInView = false; + } + else + { + //判断目标是否被墙壁遮挡 + TargetHasOcclusion = TestViewRayCast(LookTarget.GetCenterPosition()); + TestViewRayCastOver(); + + if (LookTarget is Role role) + { + TargetInViewRange = _viewTargets.Contains(role); + } + else + { + TargetInViewRange = true; + } + + TargetInView = !TargetHasOcclusion && TargetInViewRange; + } + } + } + /// /// 获取攻击的目标对象, 当 HasAttackDesire 为 true 时才会调用 /// @@ -155,20 +198,20 @@ public Role GetAttackTarget(bool perspective = true) { //目标丢失 - if (AttackTarget == null || AttackTarget.IsDestroyed || !IsEnemy(AttackTarget)) + if (_attackTarget == null || _attackTarget.IsDestroyed || !IsEnemy(_attackTarget)) { - AttackTarget = RefreshAttackTargets(AttackTarget); - return AttackTarget; + _attackTarget = RefreshAttackTargets(_attackTarget); + return _attackTarget; } if (!perspective) { //被墙阻挡 - if (TestViewRayCast(AttackTarget.GetCenterPosition())) + if (TestViewRayCast(_attackTarget.GetCenterPosition())) { - AttackTarget = RefreshAttackTargets(AttackTarget); + _attackTarget = RefreshAttackTargets(_attackTarget); TestViewRayCastOver(); - return AttackTarget; + return _attackTarget; } else { @@ -176,7 +219,7 @@ } } - return AttackTarget; + return _attackTarget; } /// @@ -286,40 +329,6 @@ } /// - /// 返回目标点是否在视野范围内 - /// - public virtual bool IsInViewRange(Vector2 target) - { - var isForward = IsPositionInForward(target); - if (isForward) - { - if (GlobalPosition.DistanceSquaredTo(target) <= ViewRange * ViewRange) //没有超出视野半径 - { - return true; - } - } - - return false; - } - - /// - /// 返回目标点是否在跟随状态下的视野半径内 - /// - public virtual bool IsInTailAfterViewRange(Vector2 target) - { - var isForward = IsPositionInForward(target); - if (isForward) - { - if (GlobalPosition.DistanceSquaredTo(target) <= TailAfterViewRange * TailAfterViewRange) //没有超出视野半径 - { - return true; - } - } - - return false; - } - - /// /// 调用视野检测, 如果被墙壁和其它物体遮挡, 则返回true /// public bool TestViewRayCast(Vector2 target) diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs index adc289d..6b171be 100644 --- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs @@ -131,7 +131,7 @@ if (Master.LookTarget != null) { //检测目标没有超出跟随视野距离 - var isInTailAfterRange = Master.IsInTailAfterViewRange(Master.LookTarget.GetCenterPosition()); + var isInTailAfterRange = Master.TargetInViewRange; if (isInTailAfterRange) { _tailAfterTimer = 0; diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFollowUpState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFollowUpState.cs index 679ed22..6ea8880 100644 --- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFollowUpState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFollowUpState.cs @@ -27,7 +27,6 @@ } _navigationUpdateTimer = 0; - Master.TargetInView = true; } public override void Process(float delta) @@ -88,18 +87,6 @@ Master.DoIdle(); } - //检测玩家是否在视野内 - if (Master.IsInTailAfterViewRange(playerPos)) - { - Master.TargetInView = !Master.TestViewRayCast(playerPos); - //关闭射线检测 - Master.TestViewRayCastOver(); - } - else - { - Master.TargetInView = false; - } - //在视野中 if (Master.TargetInView) { diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiSurroundState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiSurroundState.cs index 4760836..559a034 100644 --- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiSurroundState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiSurroundState.cs @@ -36,8 +36,7 @@ return; //throw new Exception("进入 AIAdvancedStateEnum.AiSurround 状态时角色没有攻击目标!"); } - - Master.TargetInView = true; + _isMoveOver = true; _pauseTimer = 0; _moveFlag = false; @@ -63,19 +62,6 @@ } } - var playerPos = Master.LookTarget.GetCenterPosition(); - - //检测玩家是否在视野内 - if (Master.IsInTailAfterViewRange(playerPos)) - { - Master.TargetInView = !Master.TestViewRayCast(playerPos); - //关闭射线检测 - Master.TestViewRayCastOver(); - } - else - { - Master.TargetInView = false; - } //在视野中 if (Master.TargetInView) @@ -90,7 +76,7 @@ } else if (_isMoveOver) //移动已经完成 { - RunOver(playerPos); + RunOver(Master.LookTarget.GetCenterPosition()); _isMoveOver = false; } else @@ -98,7 +84,7 @@ var masterPosition = Master.Position; if (_lockTimer >= 1) //卡在一个点超过一秒 { - RunOver(playerPos); + RunOver(Master.LookTarget.GetCenterPosition()); _isMoveOver = false; _lockTimer = 0; } @@ -147,7 +133,7 @@ var weapon = Master.WeaponPack.ActiveItem; if (weapon != null) { - if (masterPosition.DistanceSquaredTo(playerPos) > Mathf.Pow(Master.GetWeaponRange(0.7f), 2)) //玩家离开正常射击范围 + if (masterPosition.DistanceSquaredTo(Master.LookTarget.GetCenterPosition()) > Mathf.Pow(Master.GetWeaponRange(0.7f), 2)) //玩家离开正常射击范围 { ChangeState(AIStateEnum.AiFollowUp); } @@ -159,7 +145,7 @@ } else { - if (masterPosition.DistanceSquaredTo(playerPos) > Mathf.Pow(Master.ViewRange * 0.7f, 2)) //玩家离开正常射击范围 + if (masterPosition.DistanceSquaredTo(Master.LookTarget.GetCenterPosition()) > Mathf.Pow(Master.ViewRange * 0.7f, 2)) //玩家离开正常射击范围 { ChangeState(AIStateEnum.AiFollowUp); } diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiTailAfterState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiTailAfterState.cs index 00706f3..0f349ef 100644 --- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiTailAfterState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiTailAfterState.cs @@ -83,26 +83,16 @@ //站立 Master.DoIdle(); } - //检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态 - if (Master.IsInTailAfterViewRange(playerPos)) + //检测玩家是否在视野内 + if (!Master.TargetHasOcclusion) //直接看到玩家 { - if (!Master.TestViewRayCast(playerPos)) //看到玩家 - { - //关闭射线检测 - Master.TestViewRayCastOver(); - //切换成发现目标状态 - ChangeState(AIStateEnum.AiFollowUp); - return; - } - else - { - //关闭射线检测 - Master.TestViewRayCastOver(); - } + //切换成发现目标状态 + ChangeState(AIStateEnum.AiFollowUp); + return; } //检测玩家是否在穿墙视野范围内, 直接检测距离即可 - _isInViewRange = Master.IsInViewRange(playerPos); + _isInViewRange = Master.TargetInViewRange; if (_isInViewRange) { _viewTimer = 0; diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs index 1f8dd9f..f057560 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs @@ -84,8 +84,8 @@ roleState.Acceleration = enemyBase.Acceleration; roleState.Friction = enemyBase.Friction; ViewRange = enemyBase.ViewRange; + DefaultViewRange = enemyBase.ViewRange; TailAfterViewRange = enemyBase.TailAfterViewRange; - BackViewRange = enemyBase.BackViewRange; AttackInterval = enemyBase.AttackInterval; roleState.Gold = Mathf.Max(0, Utils.Random.RandomConfigRange(enemyBase.Gold)); @@ -128,27 +128,21 @@ //看向目标 if (LookTarget != null && MountLookTarget) { - if (LookTarget.IsDestroyed) + var pos = LookTarget.Position; + LookPosition = pos; + //脸的朝向 + var gPos = Position; + if (pos.X > gPos.X && Face == FaceDirection.Left) { - LookTarget = null; + Face = FaceDirection.Right; } - else + else if (pos.X < gPos.X && Face == FaceDirection.Right) { - var pos = LookTarget.Position; - LookPosition = pos; - //脸的朝向 - var gPos = Position; - if (pos.X > gPos.X && Face == FaceDirection.Left) - { - Face = FaceDirection.Right; - } - else if (pos.X < gPos.X && Face == FaceDirection.Right) - { - Face = FaceDirection.Left; - } - //枪口跟随目标 - MountPoint.SetLookAt(pos); + Face = FaceDirection.Left; } + + //枪口跟随目标 + MountPoint.SetLookAt(pos); } if (RoleState.CanPickUpWeapon)