diff --git a/DungeonShooting_Godot/src/game/activity/role/Role.cs b/DungeonShooting_Godot/src/game/activity/role/Role.cs
index dcaf930..1d2acd1 100644
--- a/DungeonShooting_Godot/src/game/activity/role/Role.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/Role.cs
@@ -941,7 +941,7 @@
_meleeAttackTimer = RoleState.MeleeAttackTime;
MountLookTarget = false;
- WeaponPack.ActiveItem.TriggerMeleeAttack(this);
+ //WeaponPack.ActiveItem.TriggerMeleeAttack(this);
//播放近战动画
PlayAnimation_MeleeAttack(() =>
{
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/AiAttackEnum.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/AiAttackEnum.cs
new file mode 100644
index 0000000..f8e8b89
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/AiAttackEnum.cs
@@ -0,0 +1,43 @@
+
+///
+/// 调用 Enemy.EnemyAttack() 函数返回的结果
+///
+public enum AiAttackEnum
+{
+ ///
+ /// 未触发 EnemyAttack()
+ ///
+ None,
+ ///
+ /// 触发切换武器
+ ///
+ ExchangeWeapon,
+ ///
+ /// 没有弹药了
+ ///
+ NoAmmo,
+ ///
+ /// 换弹中
+ ///
+ Reloading,
+ ///
+ /// 触发换弹
+ ///
+ TriggerReload,
+ ///
+ /// 没有武器
+ ///
+ NoWeapon,
+ ///
+ /// 正在锁定目标中
+ ///
+ LockingTime,
+ ///
+ /// 攻击间隙时间
+ ///
+ AttackInterval,
+ ///
+ /// 成功触发攻击
+ ///
+ Attack,
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
index 0ff19a3..1e4fa21 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
@@ -53,11 +53,9 @@
/// 导航代理中点
///
public Marker2D NavigationPoint { get; private set; }
-
- //开火间隙时间
- private float _enemyAttackTimer = 0;
- //目标在视野内的时间
- private float _targetInViewTime = 0;
+
+ //锁定目标时间
+ private float _lockTargetTime = 0;
public override void OnInit()
{
@@ -141,17 +139,31 @@
protected override void Process(float delta)
{
base.Process(delta);
- _enemyAttackTimer -= delta;
//目标在视野内的时间
var currState = StateController.CurrState;
if (currState == AiStateEnum.AiSurround || currState == AiStateEnum.AiFollowUp)
{
- _targetInViewTime += delta;
+ var weapon = WeaponPack.ActiveItem;
+ if (weapon != null)
+ {
+ if (!weapon.IsAttackIntervalTime()) //必须在可以开火时记录时间
+ {
+ _lockTargetTime += delta;
+ }
+ else
+ {
+ _lockTargetTime = 0;
+ }
+ }
+ else
+ {
+ _lockTargetTime = 0;
+ }
}
else
{
- _targetInViewTime = 0;
+ _lockTargetTime = 0;
}
EnemyPickUpWeapon();
@@ -280,57 +292,22 @@
}
///
- /// Ai触发的攻击
+ /// Ai触发的攻击, 返回是否成功触发 Attack() 函数
///
- public void EnemyAttack(float delta)
+ public AiAttackEnum EnemyAttack(float delta)
{
+ AiAttackEnum flag;
var weapon = WeaponPack.ActiveItem;
if (weapon != null)
{
- if (weapon.IsTotalAmmoEmpty()) //当前武器弹药打空
- {
- //切换到有子弹的武器
- var index = WeaponPack.FindIndex((we, i) => !we.IsTotalAmmoEmpty());
- if (index != -1)
- {
- WeaponPack.ExchangeByIndex(index);
- }
- else //所有子弹打光
- {
-
- }
- }
- else if (weapon.Reloading) //换弹中
- {
-
- }
- else if (weapon.IsAmmoEmpty()) //弹夹已经打空
- {
- Reload();
- }
- else if (_targetInViewTime >= weapon.Attribute.AiTargetLockingTime) //正常射击
- {
- if (weapon.GetDelayedAttackTime() > 0)
- {
- Attack();
- }
- else
- {
- if (weapon.Attribute.ContinuousShoot) //连发
- {
- Attack();
- }
- else //单发
- {
- if (_enemyAttackTimer <= 0)
- {
- _enemyAttackTimer = 60f / weapon.Attribute.StartFiringSpeed;
- Attack();
- }
- }
- }
- }
+ flag = weapon.AiTriggerAttack();
}
+ else //没有武器
+ {
+ flag = AiAttackEnum.NoWeapon;
+ }
+
+ return flag;
}
///
@@ -457,4 +434,20 @@
}
}
+ ///
+ /// 获取锁定目标的时间
+ ///
+ public float GetLockTargetTime()
+ {
+ return _lockTargetTime;
+ }
+
+ ///
+ /// 强制设置锁定目标时间
+ ///
+ public void SetLockTargetTime(float time)
+ {
+ _lockTargetTime = time;
+ }
+
}
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiFollowUpState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiFollowUpState.cs
index e0953eb..424de97 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiFollowUpState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiFollowUpState.cs
@@ -15,6 +15,8 @@
//导航目标点刷新计时器
private float _navigationUpdateTimer = 0;
private float _navigationInterval = 0.3f;
+ //Ai攻击状态
+ private AiAttackEnum _attackEnum;
public AiFollowUpState() : base(AiStateEnum.AiFollowUp)
{
@@ -75,11 +77,19 @@
if (!Master.NavigationAgent2D.IsNavigationFinished())
{
- //计算移动
- var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
- Master.AnimatedSprite.Play(AnimatorNames.Run);
- Master.BasisVelocity = (nextPos - masterPosition - Master.NavigationPoint.Position).Normalized() *
- Master.RoleState.MoveSpeed;
+ if (_attackEnum != AiAttackEnum.LockingTime && _attackEnum != AiAttackEnum.Attack)
+ {
+ //计算移动
+ var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
+ Master.AnimatedSprite.Play(AnimatorNames.Run);
+ Master.BasisVelocity = (nextPos - masterPosition - Master.NavigationPoint.Position).Normalized() *
+ Master.RoleState.MoveSpeed;
+ }
+ else
+ {
+ Master.AnimatedSprite.Play(AnimatorNames.Idle);
+ Master.BasisVelocity = Vector2.Zero;
+ }
}
else
{
@@ -103,7 +113,7 @@
if (inAttackRange) //在攻击范围内
{
//发起攻击
- Master.EnemyAttack(delta);
+ _attackEnum = Master.EnemyAttack(delta);
//距离够近, 可以切换到环绕模式
if (Master.GlobalPosition.DistanceSquaredTo(playerPos) <= Mathf.Pow(Utils.GetConfigRangeStart(weapon.Attribute.BulletDistanceRange), 2) * 0.7f)
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiSurroundState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiSurroundState.cs
index 1e7f4c4..9b50208 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiSurroundState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiSurroundState.cs
@@ -25,6 +25,8 @@
private Vector2 _prevPos;
//卡在一个位置的时间
private float _lockTimer;
+ //Ai攻击状态
+ private AiAttackEnum _attackEnum;
public AiSurroundState() : base(AiStateEnum.AiSurround)
{
@@ -36,6 +38,7 @@
_isMoveOver = true;
_pauseTimer = 0;
_moveFlag = false;
+ _attackEnum = AiAttackEnum.None;
}
public override void Process(float delta)
@@ -120,11 +123,19 @@
}
else
{
- //计算移动
- var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
- Master.AnimatedSprite.Play(AnimatorNames.Run);
- Master.BasisVelocity = (nextPos - pos - Master.NavigationPoint.Position).Normalized() *
- Master.RoleState.MoveSpeed;
+ if (_attackEnum != AiAttackEnum.LockingTime && _attackEnum != AiAttackEnum.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) <= 0.01f)
@@ -147,7 +158,7 @@
else
{
//发起攻击
- Master.EnemyAttack(delta);
+ _attackEnum = Master.EnemyAttack(delta);
}
}
}
diff --git a/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs b/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs
index 24bacb0..1cc974a 100644
--- a/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs
+++ b/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs
@@ -190,7 +190,7 @@
private float _upTimer = 0;
//连发次数
- private float _continuousCount = 0;
+ private int _continuousCount = 0;
//连发状态记录
private bool _continuousShootFlag = false;
@@ -682,12 +682,12 @@
{
return Master == null && GetParent() == GameApplication.Instance.World.NormalLayer;
}
-
+
///
/// 扳机函数, 调用即视为按下扳机
///
- /// 按下扳机的角色, 如果传 null, 则视为走火
- public void Trigger(Role trigger)
+ /// 按下扳机的角色, 如果传 null, 则视为走火
+ public void Trigger(Role triggerRole)
{
//不能触发扳机
if (!NoMasterCanTrigger && Master == null) return;
@@ -698,10 +698,10 @@
//更新武器属性信息
_triggerFlag = true;
_triggerRoleFlag = true;
- if (trigger != null)
+ if (triggerRole != null)
{
- TriggerRoleIsAi = trigger.IsAi;
- TriggerRoleAttackLayer = trigger.AttackLayer;
+ TriggerRoleIsAi = triggerRole.IsAi;
+ TriggerRoleAttackLayer = triggerRole.AttackLayer;
_weaponAttribute = TriggerRoleIsAi ? _aiWeaponAttribute : _playerWeaponAttribute;
}
else if (Master != null)
@@ -713,10 +713,9 @@
//是否第一帧按下
var justDown = _downTimer == 0;
-
if (_beLoadedState == 0 || _beLoadedState == -1) //需要执行上膛操作
{
- if (justDown && !Reloading && trigger != null)
+ if (justDown && !Reloading && triggerRole != null)
{
if (CurrAmmo <= 0)
{
@@ -786,7 +785,7 @@
else if (CurrAmmo <= 0) //子弹不够
{
fireFlag = false;
- if (justDown && trigger != null)
+ if (justDown && triggerRole != null)
{
//第一帧按下, 触发换弹
Reload();
@@ -831,10 +830,7 @@
}
}
}
-
- _attackFlag = true;
}
-
}
}
}
@@ -871,6 +867,22 @@
{
return _delayedTime;
}
+
+ ///
+ /// 获取当前需要连发弹药的数量, 配置了 ContinuousCountRange 时生效
+ ///
+ public int GetContinuousCount()
+ {
+ return _continuousCount;
+ }
+
+ ///
+ /// 返回是否是攻击间隙时间
+ ///
+ public bool IsAttackIntervalTime()
+ {
+ return _attackTimer > 0 || _triggerTimer > 0;
+ }
///
/// 刚按下扳机
@@ -920,6 +932,7 @@
///
private void TriggerFire()
{
+ _attackFlag = true;
_noAttackTime = 0;
//减子弹数量
@@ -1036,13 +1049,13 @@
}
}
- ///
- /// 触发武器的近战攻击
- ///
- public void TriggerMeleeAttack(Role trigger)
- {
-
- }
+ // ///
+ // /// 触发武器的近战攻击
+ // ///
+ // public virtual void TriggerMeleeAttack(Role trigger)
+ // {
+ //
+ // }
///
/// 获取武器攻击的目标层级
@@ -1892,11 +1905,90 @@
//-------------------------------- Ai相关 -----------------------------
- ///
- /// 获取 Ai 对于该武器的评分, 评分越高, 代表 Ai 会越优先选择该武器, 如果为 -1, 则表示 Ai 不会使用该武器
- ///
- public float GetAiScore()
+ public AiAttackEnum AiTriggerAttack()
{
- return 1;
+ AiAttackEnum flag;
+ if (IsTotalAmmoEmpty()) //当前武器弹药打空
+ {
+ //切换到有子弹的武器
+ var index = Master.WeaponPack.FindIndex((we, i) => !we.IsTotalAmmoEmpty());
+ if (index != -1)
+ {
+ flag = AiAttackEnum.ExchangeWeapon;
+ Master.WeaponPack.ExchangeByIndex(index);
+ }
+ else //所有子弹打光
+ {
+ flag = AiAttackEnum.NoAmmo;
+ }
+ }
+ else if (Reloading) //换弹中
+ {
+ flag = AiAttackEnum.TriggerReload;
+ }
+ else if (IsAmmoEmpty()) //弹夹已经打空
+ {
+ flag = AiAttackEnum.Reloading;
+ Reload();
+ }
+ else if (_continuousCount >= 1) //连发中
+ {
+ flag = AiAttackEnum.Attack;
+ }
+ else if (IsAttackIntervalTime()) //开火间隙
+ {
+ flag = AiAttackEnum.AttackInterval;
+ }
+ else
+ {
+ var enemy = (Enemy)Master;
+ if (enemy.GetLockTargetTime() >= Attribute.AiTargetLockingTime) //正常射击
+ {
+ if (GetDelayedAttackTime() > 0)
+ {
+ flag = AiAttackEnum.Attack;
+ enemy.Attack();
+ if (_attackFlag)
+ {
+ enemy.SetLockTargetTime(0);
+ }
+ }
+ else
+ {
+ if (Attribute.ContinuousShoot) //连发
+ {
+ flag = AiAttackEnum.Attack;
+ enemy.Attack();
+ if (_attackFlag)
+ {
+ enemy.SetLockTargetTime(0);
+ }
+ }
+ else //单发
+ {
+ flag = AiAttackEnum.Attack;
+ enemy.Attack();
+ if (_attackFlag)
+ {
+ enemy.SetLockTargetTime(0);
+ }
+ }
+ }
+ }
+ else //锁定时间没到
+ {
+ flag = AiAttackEnum.LockingTime;
+ }
+ }
+
+ return flag;
}
+
+ // ///
+ // /// 获取 Ai 对于该武器的评分, 评分越高, 代表 Ai 会越优先选择该武器, 如果为 -1, 则表示 Ai 不会使用该武器
+ // ///
+ // public float GetAiScore()
+ // {
+ // return 1;
+ // }
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/weapon/gun/Gun.cs b/DungeonShooting_Godot/src/game/activity/weapon/gun/Gun.cs
index 0d8ba1c..c5c36bd 100644
--- a/DungeonShooting_Godot/src/game/activity/weapon/gun/Gun.cs
+++ b/DungeonShooting_Godot/src/game/activity/weapon/gun/Gun.cs
@@ -37,6 +37,7 @@
{
this.CallDelay(0, () =>
{
+ Debug.Log("敌人扔掉武器触发攻击");
Trigger(master);
});
}