diff --git a/DungeonShooting_Godot/src/game/GameApplication.cs b/DungeonShooting_Godot/src/game/GameApplication.cs index 85a1beb..23d0fa6 100644 --- a/DungeonShooting_Godot/src/game/GameApplication.cs +++ b/DungeonShooting_Godot/src/game/GameApplication.cs @@ -106,7 +106,7 @@ //固定帧率 //Engine.MaxFps = TargetFps; //调试绘制开关 - ActivityObject.IsDebug = false; + ActivityObject.IsDebug = true; //Engine.TimeScale = 0.2f; //调整窗口分辨率 OnWindowSizeChanged(); diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/AIStateEnum.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/AIStateEnum.cs deleted file mode 100644 index 05dbbc5..0000000 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/AIStateEnum.cs +++ /dev/null @@ -1,36 +0,0 @@ - -public enum AiStateEnum -{ - /// - /// Ai 状态, 正常, 未发现目标 - /// - AiNormal, - // /// - // /// 发现目标, 但不知道在哪 - // /// - // AiProbe, - /// - /// 找到玩家,准备通知其他敌人 - /// - AiFind, - /// - /// 收到其他敌人通知, 前往发现目标的位置 - /// - AiLeaveFor, - /// - /// 发现目标, 目标不在视野内, 但是知道位置 - /// - AiTailAfter, - /// - /// 目标在视野内, 跟进目标, 如果距离在子弹有效射程内, 则开火 - /// - AiFollowUp, - /// - /// 距离足够近, 在目标附近随机移动 - /// - AiSurround, - /// - /// Ai 寻找弹药 - /// - AiFindAmmo, -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/AdvancedEnemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/AdvancedEnemy.cs index 7166519..cf69f1e 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/AdvancedEnemy.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/AdvancedEnemy.cs @@ -29,7 +29,7 @@ /// /// 敌人身上的状态机控制器 /// - public StateController StateController { get; private set; } + public StateController StateController { get; private set; } /// /// 视野半径, 单位像素, 发现玩家后改视野范围可以穿墙 @@ -81,7 +81,7 @@ { base.OnInit(); IsAi = true; - StateController = AddComponent>(); + StateController = AddComponent>(); AttackLayer = PhysicsLayer.Wall | PhysicsLayer.Player; EnemyLayer = PhysicsLayer.Player; @@ -104,7 +104,7 @@ StateController.Register(new AiFindAmmoState()); //默认状态 - StateController.ChangeStateInstant(AiStateEnum.AiNormal); + StateController.ChangeStateInstant(AIAdvancedStateEnum.AiNormal); } public override void EnterTree() @@ -179,7 +179,7 @@ //目标在视野内的时间 var currState = StateController.CurrState; - if (currState == AiStateEnum.AiSurround || currState == AiStateEnum.AiFollowUp) + if (currState == AIAdvancedStateEnum.AiSurround || currState == AIAdvancedStateEnum.AiFollowUp) { var weapon = WeaponPack.ActiveItem; if (weapon != null) @@ -262,9 +262,9 @@ { //受到伤害 var state = StateController.CurrState; - if (state == AiStateEnum.AiNormal || state == AiStateEnum.AiLeaveFor) //|| state == AiStateEnum.AiProbe + if (state == AIAdvancedStateEnum.AiNormal || state == AIAdvancedStateEnum.AiLeaveFor) //|| state == AiStateEnum.AiProbe { - StateController.ChangeState(AiStateEnum.AiTailAfter); + StateController.ChangeState(AIAdvancedStateEnum.AiTailAfter); } } @@ -370,7 +370,7 @@ } var currState = StateController.CurrState; - if (currState == AiStateEnum.AiNormal)// || currState == AiStateEnum.AiProbe) + if (currState == AIAdvancedStateEnum.AiNormal)// || currState == AiStateEnum.AiProbe) { //判断是否在同一个房间内 return World.Enemy_FindTargetAffiliationSet.Contains(AffiliationArea); @@ -470,7 +470,7 @@ { //这几个状态不需要主动拾起武器操作 var state = StateController.CurrState; - if (state == AiStateEnum.AiNormal) + if (state == AIAdvancedStateEnum.AiNormal) { return; } diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs index 7265228..4d2e634 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs @@ -18,7 +18,7 @@ /// /// 敌人身上的状态机控制器 /// - public StateController StateController { get; private set; } + public StateController StateController { get; private set; } /// /// 视野半径, 单位像素, 发现玩家后改视野范围可以穿墙 @@ -36,6 +36,16 @@ public float BackViewRange { get; set; } = 50; /// + /// 攻击范围 + /// + public float AttackRange { get; set; } = 200; + + /// + /// 开火时是否站立不动 + /// + public bool FiringStand { get; set; } = true; + + /// /// 视野检测射线, 朝玩家打射线, 检测是否碰到墙 /// [Export, ExportFillNode] @@ -88,7 +98,7 @@ { base.OnInit(); IsAi = true; - StateController = AddComponent>(); + StateController = AddComponent>(); AttackLayer = PhysicsLayer.Wall | PhysicsLayer.Player; EnemyLayer = PhysicsLayer.Player; @@ -102,7 +112,8 @@ StateController.Register(new AiNormalState()); StateController.Register(new AiTailAfterState()); StateController.Register(new AiFollowUpState()); - StateController.ChangeState(AiStateEnum.AiNormal); + StateController.Register(new AiSurroundState()); + StateController.ChangeState(AINormalStateEnum.AiNormal); } public override void EnterTree() @@ -132,14 +143,14 @@ { AttackState = AiAttackState.Attack; _attackTimer = AttackInterval; - EnemyAttack(); + OnAttack(); } } /// /// 敌人发动攻击 /// - public virtual void EnemyAttack() + protected virtual void OnAttack() { Debug.Log("触发攻击"); var bulletData = FireManager.GetBulletData(this, ConvertRotation(Position.AngleTo(LookPosition)), ExcelConfig.BulletBase_Map["0006"]); @@ -177,7 +188,7 @@ } //目标在视野内的时间 var currState = StateController.CurrState; - if (currState == AiStateEnum.AiSurround || currState == AiStateEnum.AiFollowUp) + if (currState == AINormalStateEnum.AiSurround || currState == AINormalStateEnum.AiFollowUp) { if (_attackTimer <= 0) //必须在可以开火时记录时间 { @@ -198,9 +209,9 @@ { //受到伤害 var state = StateController.CurrState; - if (state == AiStateEnum.AiNormal || state == AiStateEnum.AiLeaveFor) //|| state == AiStateEnum.AiProbe + if (state == AINormalStateEnum.AiNormal || state == AINormalStateEnum.AiLeaveFor) //|| state == AiStateEnum.AiProbe { - StateController.ChangeState(AiStateEnum.AiTailAfter); + StateController.ChangeState(AINormalStateEnum.AiTailAfter); } } @@ -238,7 +249,7 @@ } var currState = StateController.CurrState; - if (currState == AiStateEnum.AiNormal)// || currState == AiStateEnum.AiProbe) + if (currState == AINormalStateEnum.AiNormal)// || currState == AiStateEnum.AiProbe) { //判断是否在同一个房间内 return World.Enemy_FindTargetAffiliationSet.Contains(AffiliationArea); @@ -327,10 +338,9 @@ /// /// 获取攻击范围 /// - /// 从最小到最大距离的过渡量, 0 - 1, 默认 0.5 - public float GetAttackRange(float weight = 0.5f) + public float GetAttackRange() { - return 200; + return AttackRange; } public override float GetFirePointAltitude() diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AIAdvancedStateEnum.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AIAdvancedStateEnum.cs new file mode 100644 index 0000000..117b3c1 --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AIAdvancedStateEnum.cs @@ -0,0 +1,36 @@ + +public enum AIAdvancedStateEnum +{ + /// + /// Ai 状态, 正常, 未发现目标 + /// + AiNormal, + // /// + // /// 发现目标, 但不知道在哪 + // /// + // AiProbe, + /// + /// 找到玩家,准备通知其他敌人 + /// + AiFind, + /// + /// 收到其他敌人通知, 前往发现目标的位置 + /// + AiLeaveFor, + /// + /// 发现目标, 目标不在视野内, 但是知道位置 + /// + AiTailAfter, + /// + /// 目标在视野内, 跟进目标, 如果距离在子弹有效射程内, 则开火 + /// + AiFollowUp, + /// + /// 距离足够近, 在目标附近随机移动 + /// + AiSurround, + /// + /// Ai 寻找弹药 + /// + AiFindAmmo, +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiFindAmmoState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiFindAmmoState.cs index ab9ef33..c650113 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiFindAmmoState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiFindAmmoState.cs @@ -6,7 +6,7 @@ /// /// Ai 寻找弹药, 进入该状态需要在参数中传入目标武器对象 /// -public class AiFindAmmoState : StateBase +public class AiFindAmmoState : StateBase { private Weapon _target; @@ -18,11 +18,11 @@ private bool _isInTailAfterRange = false; private float _tailAfterTimer = 0; - public AiFindAmmoState() : base(AiStateEnum.AiFindAmmo) + public AiFindAmmoState() : base(AIAdvancedStateEnum.AiFindAmmo) { } - public override void Enter(AiStateEnum prev, params object[] args) + public override void Enter(AIAdvancedStateEnum prev, params object[] args) { if (args.Length == 0) { @@ -119,9 +119,9 @@ } } - private AiStateEnum GetNextState() + private AIAdvancedStateEnum GetNextState() { - return _tailAfterTimer > 10 ? AiStateEnum.AiNormal : AiStateEnum.AiTailAfter; + return _tailAfterTimer > 10 ? AIAdvancedStateEnum.AiNormal : AIAdvancedStateEnum.AiTailAfter; } private void SetTargetWeapon(Weapon weapon) diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiFollowUpState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiFollowUpState.cs index f635a9d..86bbe98 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiFollowUpState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiFollowUpState.cs @@ -6,17 +6,17 @@ /// /// 目标在视野内, 跟进目标, 如果距离在子弹有效射程内, 则开火 /// -public class AiFollowUpState : StateBase +public class AiFollowUpState : StateBase { //导航目标点刷新计时器 private float _navigationUpdateTimer = 0; private float _navigationInterval = 0.3f; - public AiFollowUpState() : base(AiStateEnum.AiFollowUp) + public AiFollowUpState() : base(AIAdvancedStateEnum.AiFollowUp) { } - public override void Enter(AiStateEnum prev, params object[] args) + public override void Enter(AIAdvancedStateEnum prev, params object[] args) { _navigationUpdateTimer = 0; Master.TargetInView = true; @@ -31,13 +31,13 @@ var targetWeapon = Master.FindTargetWeapon(); if (targetWeapon != null) { - ChangeState(AiStateEnum.AiFindAmmo, targetWeapon); + ChangeState(AIAdvancedStateEnum.AiFindAmmo, targetWeapon); return; } else { //切换到随机移动状态 - ChangeState(AiStateEnum.AiSurround); + ChangeState(AIAdvancedStateEnum.AiSurround); } } @@ -61,9 +61,10 @@ var inAttackRange = false; var weapon = Master.WeaponPack.ActiveItem; + var distanceSquared = masterPosition.DistanceSquaredTo(playerPos); if (weapon != null) { - inAttackRange = masterPosition.DistanceSquaredTo(playerPos) <= Mathf.Pow(Master.GetWeaponRange(0.7f), 2); + inAttackRange = distanceSquared <= Mathf.Pow(Master.GetWeaponRange(0.7f), 2); } //枪口指向玩家 @@ -112,15 +113,15 @@ Master.EnemyAttack(); //距离够近, 可以切换到环绕模式 - if (Master.GlobalPosition.DistanceSquaredTo(playerPos) <= Mathf.Pow(Utils.GetConfigRangeStart(weapon.Attribute.Bullet.DistanceRange), 2) * 0.7f) + if (distanceSquared <= Mathf.Pow(Utils.GetConfigRangeStart(weapon.Attribute.Bullet.DistanceRange), 2) * 0.7f) { - ChangeState(AiStateEnum.AiSurround); + ChangeState(AIAdvancedStateEnum.AiSurround); } } } else //不在视野中 { - ChangeState(AiStateEnum.AiTailAfter); + ChangeState(AIAdvancedStateEnum.AiTailAfter); } } diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiLeaveForState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiLeaveForState.cs index 73e339b..4c56fb2 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiLeaveForState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiLeaveForState.cs @@ -6,17 +6,17 @@ /// /// 收到其他敌人通知, 前往发现目标的位置 /// -public class AiLeaveForState : StateBase +public class AiLeaveForState : StateBase { //导航目标点刷新计时器 private float _navigationUpdateTimer = 0; private float _navigationInterval = 0.3f; - public AiLeaveForState() : base(AiStateEnum.AiLeaveFor) + public AiLeaveForState() : base(AIAdvancedStateEnum.AiLeaveFor) { } - public override void Enter(AiStateEnum prev, params object[] args) + public override void Enter(AIAdvancedStateEnum prev, params object[] args) { if (Master.World.Enemy_IsFindTarget) { @@ -35,7 +35,7 @@ var targetWeapon = Master.FindTargetWeapon(); if (targetWeapon != null) { - ChangeState(AiStateEnum.AiFindAmmo, targetWeapon); + ChangeState(AIAdvancedStateEnum.AiFindAmmo, targetWeapon); } } } @@ -79,7 +79,7 @@ //关闭射线检测 Master.TestViewRayCastOver(); //切换成发现目标状态 - ChangeState(AiStateEnum.AiFollowUp); + ChangeState(AIAdvancedStateEnum.AiFollowUp); return; } else @@ -92,7 +92,7 @@ //移动到目标掉了, 还没发现目标 if (Master.NavigationAgent2D.IsNavigationFinished()) { - ChangeState(AiStateEnum.AiNormal); + ChangeState(AIAdvancedStateEnum.AiNormal); } } diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiNormalState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiNormalState.cs index 5f469d1..13362bc 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiNormalState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiNormalState.cs @@ -6,7 +6,7 @@ /// /// AI 正常状态 /// -public class AiNormalState : StateBase +public class AiNormalState : StateBase { //是否发现玩家 private bool _isFindPlayer; @@ -32,11 +32,11 @@ //卡在一个位置的时间 private float _lockTimer; - public AiNormalState() : base(AiStateEnum.AiNormal) + public AiNormalState() : base(AIAdvancedStateEnum.AiNormal) { } - public override void Enter(AiStateEnum prev, params object[] args) + public override void Enter(AIAdvancedStateEnum prev, params object[] args) { _isFindPlayer = false; _isMoveOver = true; @@ -51,14 +51,14 @@ //其他敌人发现玩家 if (Master.CanChangeLeaveFor()) { - ChangeState(AiStateEnum.AiLeaveFor); + ChangeState(AIAdvancedStateEnum.AiLeaveFor); return; } if (_isFindPlayer) //已经找到玩家了 { //现临时处理, 直接切换状态 - ChangeState(AiStateEnum.AiTailAfter); + ChangeState(AIAdvancedStateEnum.AiTailAfter); } else //没有找到玩家 { diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiSurroundState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiSurroundState.cs index a7b2fe4..07dc504 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiSurroundState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiSurroundState.cs @@ -6,7 +6,7 @@ /// /// 距离目标足够近, 在目标附近随机移动, 并开火 /// -public class AiSurroundState : StateBase +public class AiSurroundState : StateBase { //是否移动结束 private bool _isMoveOver; @@ -23,11 +23,11 @@ //卡在一个位置的时间 private float _lockTimer; - public AiSurroundState() : base(AiStateEnum.AiSurround) + public AiSurroundState() : base(AIAdvancedStateEnum.AiSurround) { } - public override void Enter(AiStateEnum prev, params object[] args) + public override void Enter(AIAdvancedStateEnum prev, params object[] args) { Master.TargetInView = true; _isMoveOver = true; @@ -44,7 +44,7 @@ var targetWeapon = Master.FindTargetWeapon(); if (targetWeapon != null) { - ChangeState(AiStateEnum.AiFindAmmo, targetWeapon); + ChangeState(AIAdvancedStateEnum.AiFindAmmo, targetWeapon); return; } } @@ -85,6 +85,7 @@ } else { + var masterPosition = Master.GlobalPosition; if (_lockTimer >= 1) //卡在一个点超过一秒 { RunOver(playerPos); @@ -105,12 +106,12 @@ var nextPos = Master.NavigationAgent2D.GetNextPathPosition(); Master.AnimatedSprite.Play(AnimatorNames.Run); Master.BasisVelocity = - (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() * + (nextPos - masterPosition - Master.NavigationPoint.Position).Normalized() * Master.RoleState.MoveSpeed; } else { - var pos = Master.GlobalPosition; + var pos = masterPosition; var lastSlideCollision = Master.GetLastSlideCollision(); if (lastSlideCollision != null && lastSlideCollision.GetCollider() is AdvancedRole) //碰到其他角色 { @@ -138,7 +139,7 @@ } } - if (_prevPos.DistanceSquaredTo(pos) <= 0.01f) + if (_prevPos.DistanceSquaredTo(pos) <= 1 * delta) { _lockTimer += delta; } @@ -150,10 +151,9 @@ if (weapon != null) { - var position = Master.GlobalPosition; - if (position.DistanceSquaredTo(playerPos) > Mathf.Pow(Master.GetWeaponRange(0.7f), 2)) //玩家离开正常射击范围 + if (masterPosition.DistanceSquaredTo(playerPos) > Mathf.Pow(Master.GetWeaponRange(0.7f), 2)) //玩家离开正常射击范围 { - ChangeState(AiStateEnum.AiFollowUp); + ChangeState(AIAdvancedStateEnum.AiFollowUp); } else { @@ -165,7 +165,7 @@ } else //目标离开视野 { - ChangeState(AiStateEnum.AiTailAfter); + ChangeState(AIAdvancedStateEnum.AiTailAfter); } } diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiTailAfterState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiTailAfterState.cs index 569690e..96fc91c 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiTailAfterState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiTailAfterState.cs @@ -6,7 +6,7 @@ /// /// AI 发现玩家, 跟随玩家 /// -public class AiTailAfterState : StateBase +public class AiTailAfterState : StateBase { /// /// 目标是否在视野半径内 @@ -20,11 +20,11 @@ //目标从视野消失时已经过去的时间 private float _viewTimer; - public AiTailAfterState() : base(AiStateEnum.AiTailAfter) + public AiTailAfterState() : base(AIAdvancedStateEnum.AiTailAfter) { } - public override void Enter(AiStateEnum prev, params object[] args) + public override void Enter(AIAdvancedStateEnum prev, params object[] args) { _isInViewRange = true; _navigationUpdateTimer = 0; @@ -37,7 +37,7 @@ var targetWeapon = Master.FindTargetWeapon(); if (targetWeapon != null) { - ChangeState(AiStateEnum.AiFindAmmo, targetWeapon); + ChangeState(AIAdvancedStateEnum.AiFindAmmo, targetWeapon); } } } @@ -93,7 +93,7 @@ //关闭射线检测 Master.TestViewRayCastOver(); //切换成发现目标状态 - ChangeState(AiStateEnum.AiFollowUp); + ChangeState(AIAdvancedStateEnum.AiFollowUp); return; } else @@ -113,7 +113,7 @@ { if (_viewTimer > 10) //10秒 { - ChangeState(AiStateEnum.AiNormal); + ChangeState(AIAdvancedStateEnum.AiNormal); } else { diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AINormalStateEnum.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AINormalStateEnum.cs new file mode 100644 index 0000000..447e4e6 --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AINormalStateEnum.cs @@ -0,0 +1,33 @@ +namespace NnormalState; + +public enum AINormalStateEnum +{ + /// + /// Ai 状态, 正常, 未发现目标 + /// + AiNormal, + // /// + // /// 发现目标, 但不知道在哪 + // /// + // AiProbe, + /// + /// 找到玩家,准备通知其他敌人 + /// + AiFind, + /// + /// 收到其他敌人通知, 前往发现目标的位置 + /// + AiLeaveFor, + /// + /// 发现目标, 目标不在视野内, 但是知道位置 + /// + AiTailAfter, + /// + /// 目标在视野内, 跟进目标, 如果距离在子弹有效射程内, 则开火 + /// + AiFollowUp, + /// + /// 距离足够近, 在目标附近随机移动 + /// + AiSurround, +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiFollowUpState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiFollowUpState.cs index c4ec235..b0185de 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiFollowUpState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiFollowUpState.cs @@ -6,17 +6,17 @@ /// /// 目标在视野内, 跟进目标, 如果距离在子弹有效射程内, 则开火 /// -public class AiFollowUpState : StateBase +public class AiFollowUpState : StateBase { //导航目标点刷新计时器 private float _navigationUpdateTimer = 0; private float _navigationInterval = 0.3f; - public AiFollowUpState() : base(AiStateEnum.AiFollowUp) + public AiFollowUpState() : base(AINormalStateEnum.AiFollowUp) { } - public override void Enter(AiStateEnum prev, params object[] args) + public override void Enter(AINormalStateEnum prev, params object[] args) { _navigationUpdateTimer = 0; Master.TargetInView = true; @@ -39,9 +39,9 @@ } var masterPosition = Master.GlobalPosition; - + var distanceSquared = masterPosition.DistanceSquaredTo(playerPos); //是否在攻击范围内 - var inAttackRange = masterPosition.DistanceSquaredTo(playerPos) <= Mathf.Pow(Master.GetAttackRange(0.7f), 2); + var inAttackRange = distanceSquared <= Mathf.Pow(Master.GetAttackRange(), 2); //枪口指向玩家 Master.LookTargetPosition(playerPos); @@ -89,15 +89,15 @@ Master.Attack(); //距离够近, 可以切换到环绕模式 - // if (Master.GlobalPosition.DistanceSquaredTo(playerPos) <= Mathf.Pow(Utils.GetConfigRangeStart(weapon.Attribute.Bullet.DistanceRange), 2) * 0.7f) - // { - // ChangeState(AiStateEnum.AiSurround); - // } + if (distanceSquared <= Mathf.Pow(Master.GetAttackRange() * 0.7f, 2) * 0.7f) + { + ChangeState(AINormalStateEnum.AiSurround); + } } } else //不在视野中 { - ChangeState(AiStateEnum.AiTailAfter); + ChangeState(AINormalStateEnum.AiTailAfter); } } diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiNormalState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiNormalState.cs index 9cf340a..e991e00 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiNormalState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiNormalState.cs @@ -5,7 +5,7 @@ /// /// AI 正常状态 /// -public class AiNormalState : StateBase +public class AiNormalState : StateBase { //是否发现玩家 private bool _isFindPlayer; @@ -31,11 +31,11 @@ //卡在一个位置的时间 private float _lockTimer; - public AiNormalState() : base(AiStateEnum.AiNormal) + public AiNormalState() : base(AINormalStateEnum.AiNormal) { } - public override void Enter(AiStateEnum prev, params object[] args) + public override void Enter(AINormalStateEnum prev, params object[] args) { _isFindPlayer = false; _isMoveOver = true; @@ -50,14 +50,14 @@ //其他敌人发现玩家 if (Master.CanChangeLeaveFor()) { - ChangeState(AiStateEnum.AiLeaveFor); + ChangeState(AINormalStateEnum.AiLeaveFor); return; } if (_isFindPlayer) //已经找到玩家了 { //现临时处理, 直接切换状态 - ChangeState(AiStateEnum.AiTailAfter); + ChangeState(AINormalStateEnum.AiTailAfter); } else //没有找到玩家 { diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiSurroundState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiSurroundState.cs new file mode 100644 index 0000000..b66e1fb --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiSurroundState.cs @@ -0,0 +1,170 @@ + +using Godot; + +namespace NnormalState; + +/// +/// 距离目标足够近, 在目标附近随机移动, 并开火 +/// +public class AiSurroundState : StateBase +{ + //是否移动结束 + private bool _isMoveOver; + + //移动停顿计时器 + private float _pauseTimer; + private bool _moveFlag; + + //下一个移动点 + private Vector2 _nextPosition; + + //上一帧位置 + private Vector2 _prevPos; + //卡在一个位置的时间 + private float _lockTimer; + + public AiSurroundState() : base(AINormalStateEnum.AiSurround) + { + } + + public override void Enter(AINormalStateEnum prev, params object[] args) + { + Master.TargetInView = true; + _isMoveOver = true; + _pauseTimer = 0; + _moveFlag = false; + } + + public override void Process(float delta) + { + var playerPos = Player.Current.GetCenterPosition(); + + //枪口指向玩家 + Master.LookTargetPosition(playerPos); + + //检测玩家是否在视野内 + if (Master.IsInTailAfterViewRange(playerPos)) + { + Master.TargetInView = !Master.TestViewRayCast(playerPos); + //关闭射线检测 + Master.TestViewRayCastOver(); + } + else + { + Master.TargetInView = false; + } + + //在视野中, 或者锁敌状态下, 或者攻击状态下, 继续保持原本逻辑 + if (Master.TargetInView || + (Master.FiringStand && + (Master.AttackState == AiAttackState.LockingTime || Master.AttackState == AiAttackState.Attack) + )) + { + if (_pauseTimer >= 0) + { + Master.AnimatedSprite.Play(AnimatorNames.Idle); + _pauseTimer -= delta; + } + else if (_isMoveOver) //移动已经完成 + { + RunOver(playerPos); + _isMoveOver = false; + } + else + { + var masterPosition = Master.GlobalPosition; + if (_lockTimer >= 1) //卡在一个点超过一秒 + { + RunOver(playerPos); + _isMoveOver = false; + _lockTimer = 0; + } + else if (Master.NavigationAgent2D.IsNavigationFinished()) //到达终点 + { + _pauseTimer = Utils.Random.RandomRangeFloat(0f, 0.5f); + _isMoveOver = true; + _moveFlag = false; + Master.BasisVelocity = Vector2.Zero; + } + else if (!_moveFlag) + { + _moveFlag = true; + //计算移动 + var nextPos = Master.NavigationAgent2D.GetNextPathPosition(); + Master.AnimatedSprite.Play(AnimatorNames.Run); + Master.BasisVelocity = + (nextPos - masterPosition - Master.NavigationPoint.Position).Normalized() * + Master.RoleState.MoveSpeed; + } + else + { + var pos = masterPosition; + var lastSlideCollision = Master.GetLastSlideCollision(); + if (lastSlideCollision != null && lastSlideCollision.GetCollider() is AdvancedRole) //碰到其他角色 + { + _pauseTimer = Utils.Random.RandomRangeFloat(0f, 0.3f); + _isMoveOver = true; + _moveFlag = false; + Master.BasisVelocity = Vector2.Zero; + } + else + { + //判断开火状态, 进行移动 + if (!Master.FiringStand || + (Master.AttackState != AiAttackState.LockingTime && Master.AttackState != AiAttackState.Attack)) + { //正常移动 + //计算移动 + var nextPos = Master.NavigationAgent2D.GetNextPathPosition(); + Master.AnimatedSprite.Play(AnimatorNames.Run); + Master.BasisVelocity = (nextPos - pos - Master.NavigationPoint.Position).Normalized() * + Master.RoleState.MoveSpeed; + } + else //站立不动 + { + Master.AnimatedSprite.Play(AnimatorNames.Idle); + Master.BasisVelocity = Vector2.Zero; + } + } + + if (_prevPos.DistanceSquaredTo(pos) <= 1 * delta) + { + _lockTimer += delta; + } + else + { + _prevPos = pos; + } + } + + if (masterPosition.DistanceSquaredTo(playerPos) > Mathf.Pow(Master.GetAttackRange() * 0.7f, 2)) //玩家离开正常射击范围 + { + ChangeState(AINormalStateEnum.AiFollowUp); + } + else + { + //发起攻击 + Master.Attack(); + } + } + } + else //目标离开视野 + { + ChangeState(AINormalStateEnum.AiTailAfter); + } + } + + private void RunOver(Vector2 targetPos) + { + var distance = (int)(Master.GetAttackRange() * 0.7f); + _nextPosition = new Vector2( + targetPos.X + Utils.Random.RandomRangeInt(-distance, distance), + targetPos.Y + Utils.Random.RandomRangeInt(-distance, distance) + ); + Master.NavigationAgent2D.TargetPosition = _nextPosition; + } + + public override void DebugDraw() + { + Master.DrawLine(new Vector2(0, -8), Master.ToLocal(_nextPosition), Colors.White); + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiTailAfterState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiTailAfterState.cs index 3d29972..fe894e2 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiTailAfterState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiTailAfterState.cs @@ -6,7 +6,7 @@ /// /// AI 发现玩家, 跟随玩家 /// -public class AiTailAfterState : StateBase +public class AiTailAfterState : StateBase { /// /// 目标是否在视野半径内 @@ -20,11 +20,11 @@ //目标从视野消失时已经过去的时间 private float _viewTimer; - public AiTailAfterState() : base(AiStateEnum.AiTailAfter) + public AiTailAfterState() : base(AINormalStateEnum.AiTailAfter) { } - public override void Enter(AiStateEnum prev, params object[] args) + public override void Enter(AINormalStateEnum prev, params object[] args) { _isInViewRange = true; _navigationUpdateTimer = 0; @@ -80,7 +80,7 @@ //关闭射线检测 Master.TestViewRayCastOver(); //切换成发现目标状态 - ChangeState(AiStateEnum.AiFollowUp); + ChangeState(AINormalStateEnum.AiFollowUp); return; } else @@ -100,7 +100,7 @@ { if (_viewTimer > 10) //10秒 { - ChangeState(AiStateEnum.AiNormal); + ChangeState(AINormalStateEnum.AiNormal); } else { diff --git a/DungeonShooting_Godot/src/game/room/DungeonManager.cs b/DungeonShooting_Godot/src/game/room/DungeonManager.cs index 09a0576..e53840c 100644 --- a/DungeonShooting_Godot/src/game/room/DungeonManager.cs +++ b/DungeonShooting_Godot/src/game/room/DungeonManager.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using Godot; +using NnormalState; /// /// 地牢管理器 @@ -569,16 +570,16 @@ { if (enemy is Enemy e) { - if (e.StateController.CurrState != AiStateEnum.AiNormal) + if (e.StateController.CurrState != AINormalStateEnum.AiNormal) { - e.StateController.ChangeState(AiStateEnum.AiNormal); + e.StateController.ChangeState(AINormalStateEnum.AiNormal); } } else if (enemy is AdvancedEnemy ae) { - if (ae.StateController.CurrState != AiStateEnum.AiNormal) + if (ae.StateController.CurrState != AIAdvancedStateEnum.AiNormal) { - ae.StateController.ChangeState(AiStateEnum.AiNormal); + ae.StateController.ChangeState(AIAdvancedStateEnum.AiNormal); } } else @@ -644,29 +645,39 @@ for (var i = 0; i < World.Enemy_InstanceList.Count; i++) { var enemy = World.Enemy_InstanceList[i]; - AiStateEnum state; if (enemy is Enemy e) { - state = e.StateController.CurrState; + var state = e.StateController.CurrState; + if (state == AINormalStateEnum.AiFollowUp || state == AINormalStateEnum.AiSurround) //目标在视野内 + { + if (!World.Enemy_IsFindTarget) + { + World.Enemy_IsFindTarget = true; + World.Enemy_FindTargetPosition = Player.Current.GetCenterPosition(); + World.Enemy_FindTargetAffiliationSet.Add(Player.Current.AffiliationArea); + } + World.Enemy_FindTargetAffiliationSet.Add(enemy.AffiliationArea); + } } else if (enemy is AdvancedEnemy ae) { - state = ae.StateController.CurrState; + var state = ae.StateController.CurrState; + if (state == AIAdvancedStateEnum.AiFollowUp || state == AIAdvancedStateEnum.AiSurround) //目标在视野内 + { + if (!World.Enemy_IsFindTarget) + { + World.Enemy_IsFindTarget = true; + World.Enemy_FindTargetPosition = Player.Current.GetCenterPosition(); + World.Enemy_FindTargetAffiliationSet.Add(Player.Current.AffiliationArea); + } + World.Enemy_FindTargetAffiliationSet.Add(enemy.AffiliationArea); + } } else { throw new Exception("World.Enemy_InstanceList 混入了非 Enemy 和 AdvancedEnemy 类型的对象!"); } - if (state == AiStateEnum.AiFollowUp || state == AiStateEnum.AiSurround) //目标在视野内 - { - if (!World.Enemy_IsFindTarget) - { - World.Enemy_IsFindTarget = true; - World.Enemy_FindTargetPosition = Player.Current.GetCenterPosition(); - World.Enemy_FindTargetAffiliationSet.Add(Player.Current.AffiliationArea); - } - World.Enemy_FindTargetAffiliationSet.Add(enemy.AffiliationArea); - } + } }