diff --git a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs
index c88e33f..5080d9b 100644
--- a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs
+++ b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs
@@ -1727,4 +1727,12 @@
}
_freezeSprite.Unfreeze();
}
+
+ ///
+ /// 获取中心点坐标
+ ///
+ public Vector2 GetCenterPosition()
+ {
+ return AnimatedSprite.Position + Position;
+ }
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/activity/components/StateBase.cs b/DungeonShooting_Godot/src/framework/activity/components/StateBase.cs
index ce71a11..42a8e57 100644
--- a/DungeonShooting_Godot/src/framework/activity/components/StateBase.cs
+++ b/DungeonShooting_Godot/src/framework/activity/components/StateBase.cs
@@ -49,15 +49,6 @@
}
///
- /// 是否允许切换至下一个状态, 该函数由状态机控制器调用, 不需要手动调用
- ///
- /// 下一个状态类型
- public virtual bool CanChangeState(S next)
- {
- return true;
- }
-
- ///
/// 从当前状态退出时调用
///
/// 下一个状态类型
diff --git a/DungeonShooting_Godot/src/framework/activity/components/StateController.cs b/DungeonShooting_Godot/src/framework/activity/components/StateController.cs
index f1b035c..942dd5f 100644
--- a/DungeonShooting_Godot/src/framework/activity/components/StateController.cs
+++ b/DungeonShooting_Godot/src/framework/activity/components/StateController.cs
@@ -133,7 +133,7 @@
CurrStateBase = newState;
newState.Enter(default, arg);
}
- else if (CurrStateBase.CanChangeState(next))
+ else
{
// Debug.Log($"changeState: {CurrState} => {next}");
_isChangeState = !late;
diff --git a/DungeonShooting_Godot/src/game/activity/bullet/explode/Explode.cs b/DungeonShooting_Godot/src/game/activity/bullet/explode/Explode.cs
index d21bca8..50a9e22 100644
--- a/DungeonShooting_Godot/src/game/activity/bullet/explode/Explode.cs
+++ b/DungeonShooting_Godot/src/game/activity/bullet/explode/Explode.cs
@@ -30,6 +30,10 @@
///
public uint AttackLayer { get; private set; }
+ ///
+ /// 产生爆炸的子弹数据
+ ///
+ public BulletData BulletData { get; private set; }
private bool _init = false;
private float _hitRadius;
@@ -51,13 +55,13 @@
///
/// 初始化爆炸数据
///
- /// 爆炸所在区域
+ /// 产生爆炸的子弹数据
/// 攻击的层级
/// 伤害半径
/// 造成的伤害
/// 击退半径
/// 最大击退速度
- public void Init(AffiliationArea affiliationArea, uint attackLayer, float hitRadius, int harm, float repelledRadius, float maxRepelled)
+ public void Init(BulletData bulletData, uint attackLayer, float hitRadius, int harm, float repelledRadius, float maxRepelled)
{
if (!_init)
{
@@ -68,7 +72,8 @@
AnimationPlayer.AnimationFinished += OnAnimationFinish;
BodyEntered += OnBodyEntered;
}
-
+
+ BulletData = bulletData;
AttackLayer = attackLayer;
_hitRadius = hitRadius;
_harm = harm;
@@ -78,6 +83,7 @@
CircleShape.Radius = Mathf.Max(hitRadius, maxRepelled);
//冲击波
+ var affiliationArea = bulletData.TriggerRole?.AffiliationArea;
if (affiliationArea != null)
{
ShockWave(affiliationArea);
@@ -138,7 +144,7 @@
{
if (o is Role role) //是角色
{
- role.CallDeferred(nameof(role.Hurt), _harm, angle);
+ role.CallDeferred(nameof(role.Hurt), BulletData.TriggerRole, _harm, angle);
}
else if (o is Bullet bullet) //是子弹
{
diff --git a/DungeonShooting_Godot/src/game/activity/bullet/laser/Laser.cs b/DungeonShooting_Godot/src/game/activity/bullet/laser/Laser.cs
index 5a62788..5722fce 100644
--- a/DungeonShooting_Godot/src/game/activity/bullet/laser/Laser.cs
+++ b/DungeonShooting_Godot/src/game/activity/bullet/laser/Laser.cs
@@ -145,7 +145,7 @@
role.MoveController.AddForce(Vector2.FromAngle(Rotation) * BulletData.Repel);
}
//造成伤害
- role.CallDeferred(nameof(Role.Hurt), BulletData.Harm, Rotation);
+ role.CallDeferred(nameof(Role.Hurt), BulletData.TriggerRole, BulletData.Harm, Rotation);
}
}
diff --git a/DungeonShooting_Godot/src/game/activity/bullet/normal/BoomBullet.cs b/DungeonShooting_Godot/src/game/activity/bullet/normal/BoomBullet.cs
index 447f5a7..065162f 100644
--- a/DungeonShooting_Godot/src/game/activity/bullet/normal/BoomBullet.cs
+++ b/DungeonShooting_Godot/src/game/activity/bullet/normal/BoomBullet.cs
@@ -71,7 +71,7 @@
explode.Position = pos;
explode.RotationDegrees = Utils.Random.RandomRangeInt(0, 360);
explode.AddToActivityRootDeferred(RoomLayerEnum.YSortLayer);
- explode.Init(BulletData.TriggerRole?.AffiliationArea, AttackLayer, 25, BulletData.Harm, 50, BulletData.Repel);
+ explode.Init(BulletData, AttackLayer, 25, BulletData.Harm, 50, BulletData.Repel);
explode.RunPlay(BulletData.TriggerRole);
if (AffiliationArea != null)
{
diff --git a/DungeonShooting_Godot/src/game/activity/bullet/normal/Bullet.cs b/DungeonShooting_Godot/src/game/activity/bullet/normal/Bullet.cs
index a3d59c1..407c461 100644
--- a/DungeonShooting_Godot/src/game/activity/bullet/normal/Bullet.cs
+++ b/DungeonShooting_Godot/src/game/activity/bullet/normal/Bullet.cs
@@ -146,7 +146,7 @@
}
//造成伤害
- role.CallDeferred(nameof(AdvancedRole.Hurt), BulletData.Harm, Rotation);
+ role.CallDeferred(nameof(AdvancedRole.Hurt), BulletData.TriggerRole, BulletData.Harm, Rotation);
//穿透次数
CurrentPenetration++;
diff --git a/DungeonShooting_Godot/src/game/activity/role/AdvancedRole.cs b/DungeonShooting_Godot/src/game/activity/role/AdvancedRole.cs
index c3dfc4b..c1350c1 100644
--- a/DungeonShooting_Godot/src/game/activity/role/AdvancedRole.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/AdvancedRole.cs
@@ -147,11 +147,6 @@
});
}
- public override Vector2 GetCenterPosition()
- {
- return MountPoint.GlobalPosition;
- }
-
public override void LookTargetPosition(Vector2 pos)
{
LookPosition = pos;
@@ -385,7 +380,7 @@
role.MoveController.AddForce(v2);
}
- role.CallDeferred(nameof(Hurt), damage, (role.GetCenterPosition() - GlobalPosition).Angle());
+ role.CallDeferred(nameof(Hurt), this, damage, (role.GetCenterPosition() - GlobalPosition).Angle());
}
else if (activityObject is Bullet bullet) //攻击子弹
{
diff --git a/DungeonShooting_Godot/src/game/activity/role/Role.cs b/DungeonShooting_Godot/src/game/activity/role/Role.cs
index 1634e09..ee675a6 100644
--- a/DungeonShooting_Godot/src/game/activity/role/Role.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/Role.cs
@@ -275,9 +275,10 @@
///
/// 当受伤时调用
///
+ /// 谁触发的伤害
/// 受到的伤害
/// 是否受到真实伤害, 如果为false, 则表示该伤害被互动格挡掉了
- protected virtual void OnHit(int damage, bool realHarm)
+ protected virtual void OnHit(ActivityObject target, int damage, bool realHarm)
{
}
@@ -503,14 +504,6 @@
}
///
- /// 获取当前角色的中心点坐标
- ///
- public virtual Vector2 GetCenterPosition()
- {
- return AnimatedSprite.GlobalPosition;
- }
-
- ///
/// 使角色看向指定的坐标的方向
///
public virtual void LookTargetPosition(Vector2 pos)
@@ -675,9 +668,10 @@
///
/// 受到伤害, 如果是在碰撞信号处理函数中调用该函数, 请使用 CallDeferred 来延时调用, 否则很有可能导致报错
///
+ /// 谁触发的伤害
/// 伤害的量
/// 伤害角度(弧度制)
- public virtual void Hurt(int damage, float angle)
+ public virtual void Hurt(ActivityObject target, int damage, float angle)
{
//受伤闪烁, 无敌状态
if (Invincible)
@@ -706,7 +700,7 @@
// blood.Rotation = angle;
// GameApplication.Instance.Node3D.GetRoot().AddChild(blood);
}
- OnHit(damage, !flag);
+ OnHit(target, damage, !flag);
//受伤特效
PlayHitAnimation();
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/AdvancedEnemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/AdvancedEnemy.cs
index ea5c57b..5052136 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/AdvancedEnemy.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/AdvancedEnemy.cs
@@ -73,7 +73,7 @@
/// 锁定目标已经走过的时间
///
public float LockTargetTime { get; set; } = 0;
-
+
public override void OnInit()
{
base.OnInit();
@@ -100,6 +100,8 @@
StateController.Register(new AiSurroundState());
StateController.Register(new AiFindAmmoState());
StateController.Register(new AiAttackState());
+ StateController.Register(new AiAstonishedState());
+ StateController.Register(new AiNotifyState());
//默认状态
StateController.ChangeStateInstant(AIAdvancedStateEnum.AiNormal);
@@ -179,12 +181,13 @@
EnemyPickUpWeapon();
}
- protected override void OnHit(int damage, bool realHarm)
+ protected override void OnHit(ActivityObject target, int damage, bool realHarm)
{
//受到伤害
var state = StateController.CurrState;
if (state == AIAdvancedStateEnum.AiNormal || state == AIAdvancedStateEnum.AiLeaveFor) //|| state == AiStateEnum.AiProbe
{
+ LookTarget = target;
StateController.ChangeState(AIAdvancedStateEnum.AiTailAfter);
}
}
@@ -281,26 +284,6 @@
}
///
- /// 检查是否能切换到 AiStateEnum.AiLeaveFor 状态
- ///
- public bool CanChangeLeaveFor()
- {
- if (!World.Enemy_IsFindTarget)
- {
- return false;
- }
-
- var currState = StateController.CurrState;
- if (currState == AIAdvancedStateEnum.AiNormal)// || currState == AiStateEnum.AiProbe)
- {
- //判断是否在同一个房间内
- return World.Enemy_FindTargetAffiliationSet.Contains(AffiliationArea);
- }
-
- return false;
- }
-
- ///
/// 获取武器攻击范围 (最大距离值与最小距离的中间值)
///
/// 从最小到最大距离的过渡量, 0 - 1, 默认 0.5
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
index b6f69a0..d97e5f9 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
@@ -179,13 +179,14 @@
}
}
- protected override void OnHit(int damage, bool realHarm)
+ protected override void OnHit(ActivityObject target, int damage, bool realHarm)
{
//受到伤害
var state = StateController.CurrState;
if (state == AINormalStateEnum.AiNormal || state == AINormalStateEnum.AiLeaveFor) //|| state == AiStateEnum.AiProbe
{
- StateController.ChangeState(AINormalStateEnum.AiTailAfter);
+ LookTarget = target;
+ StateController.ChangeState(AINormalStateEnum.AiTailAfter, target);
}
}
@@ -213,26 +214,6 @@
}
///
- /// 检查是否能切换到 AiStateEnum.AiLeaveFor 状态
- ///
- public bool CanChangeLeaveFor()
- {
- if (!World.Enemy_IsFindTarget)
- {
- return false;
- }
-
- var currState = StateController.CurrState;
- if (currState == AINormalStateEnum.AiNormal)// || currState == AiStateEnum.AiProbe)
- {
- //判断是否在同一个房间内
- return World.Enemy_FindTargetAffiliationSet.Contains(AffiliationArea);
- }
-
- return false;
- }
-
- ///
/// 返回目标点是否在视野范围内
///
public bool IsInViewRange(Vector2 target)
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AIAdvancedStateEnum.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AIAdvancedStateEnum.cs
index a9c963d..c02b0d2 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AIAdvancedStateEnum.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AIAdvancedStateEnum.cs
@@ -8,7 +8,7 @@
///
/// 找到玩家,准备通知其他敌人
///
- AiFind,
+ AiNotify,
///
/// 惊讶状态
///
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiAstonishedState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiAstonishedState.cs
new file mode 100644
index 0000000..bc07574
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiAstonishedState.cs
@@ -0,0 +1,64 @@
+using Godot;
+
+namespace AdvancedState;
+
+///
+/// 发现目标时的惊讶状态
+///
+public class AiAstonishedState : StateBase
+{
+ ///
+ /// 下一个状态
+ ///
+ public AIAdvancedStateEnum NextState;
+
+ private object[] _args;
+ private float _timer;
+
+ public AiAstonishedState() : base(AIAdvancedStateEnum.AiAstonished)
+ {
+ }
+
+ public override void Enter(AIAdvancedStateEnum prev, params object[] args)
+ {
+ if (args.Length == 0)
+ {
+ Debug.Log("进入 AINormalStateEnum.AiAstonished 状态必传入下一个状态做完参数!");
+ ChangeState(prev);
+ return;
+ }
+
+ NextState = (AIAdvancedStateEnum)args[0];
+ _args = args;
+ _timer = 0.6f;
+
+ if (NextState == AIAdvancedStateEnum.AiLeaveFor)
+ {
+ var target = (ActivityObject)args[1];
+ Master.LookTargetPosition(target.GetCenterPosition());
+ }
+ }
+
+ public override void Process(float delta)
+ {
+ Master.DoIdle();
+ //播放惊讶表情
+
+ _timer -= delta;
+ if (_timer <= 0)
+ {
+ if (_args.Length == 1)
+ {
+ ChangeState(NextState);
+ }
+ else if (_args.Length == 2)
+ {
+ ChangeState(NextState, _args[1]);
+ }
+ else if (_args.Length == 3)
+ {
+ ChangeState(NextState, _args[1], _args[2]);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiAttackState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiAttackState.cs
index f4f690d..7d8b30d 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiAttackState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiAttackState.cs
@@ -1,4 +1,5 @@
-using Godot;
+using System;
+using Godot;
namespace AdvancedState;
@@ -38,19 +39,21 @@
public override void Enter(AIAdvancedStateEnum prev, params object[] args)
{
+ if (Master.LookTarget == null)
+ {
+ throw new Exception("进入 AIAdvancedStateEnum.AiAttack 状态时角色没有攻击目标!");
+ }
+
var weapon = Master.WeaponPack.ActiveItem;
if (weapon == null)
{
- Debug.LogError("进入 AIAdvancedStateEnum.AiAttack 状态时角色没有武器!");
- ChangeState(prev);
- return;
+ throw new Exception("进入 AIAdvancedStateEnum.AiAttack 状态时角色没有武器!");
+
}
if (!weapon.TriggerIsReady())
{
- Debug.LogError("进入 AIAdvancedStateEnum.AiAttack 状态时角色武器还玩法触动扳机!");
- ChangeState(prev);
- return;
+ throw new Exception("进入 AIAdvancedStateEnum.AiAttack 状态时角色武器还玩法触动扳机!");
}
Master.BasisVelocity = Vector2.Zero;
@@ -67,13 +70,10 @@
{
Master.MountLookTarget = true;
Master.LockTargetTime = 0;
- Master.LookTarget = null;
}
public override void Process(float delta)
{
- Master.LookTarget = Player.Current;
-
var weapon = Master.WeaponPack.ActiveItem;
if (weapon == null)
{
@@ -84,6 +84,7 @@
{
if (weapon.GetAttackTimer() <= 0) //攻击冷却完成
{
+ Master.MountLookTarget = true;
//这里要做换弹判断, 还有上膛判断
if (weapon.CurrAmmo <= 0) //换弹判断
{
@@ -194,7 +195,7 @@
}
else if (_isMoveOver) //移动已经完成
{
- RunOver(Player.Current.Position);
+ RunOver(Master.LookTarget.Position);
_isMoveOver = false;
}
else
@@ -202,7 +203,7 @@
var masterPosition = Master.Position;
if (_lockTimer >= 1) //卡在一个点超过一秒
{
- RunOver(Player.Current.Position);
+ RunOver(Master.LookTarget.Position);
_isMoveOver = false;
_lockTimer = 0;
}
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 0019e00..3857cea 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiFindAmmoState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiFindAmmoState.cs
@@ -1,4 +1,5 @@
+using System;
using Godot;
namespace AdvancedState;
@@ -24,11 +25,14 @@
public override void Enter(AIAdvancedStateEnum prev, params object[] args)
{
+ if (Master.LookTarget == null)
+ {
+ throw new Exception("进入 AIAdvancedStateEnum.AiFindAmmo 状态时角色没有攻击目标!");
+ }
+
if (args.Length == 0)
{
- Debug.LogError("进入 AiStateEnum.AiFindAmmo 状态必须要把目标武器当成参数传过来");
- ChangeState(prev);
- return;
+ throw new Exception("进入 AiStateEnum.AiFindAmmo 状态必须要把目标武器当成参数传过来");
}
SetTargetWeapon((Weapon)args[0]);
@@ -40,11 +44,6 @@
_target.SetSign(SignNames.AiFindWeaponSign, Master);
}
- public override void Exit(AIAdvancedStateEnum next)
- {
- Master.LookTarget = null;
- }
-
public override void Process(float delta)
{
if (!Master.IsAllWeaponTotalAmmoEmpty()) //已经有弹药了
@@ -65,9 +64,6 @@
{
_navigationUpdateTimer -= delta;
}
-
- //枪口指向玩家
- Master.LookTarget = Player.Current;
if (_target.IsDestroyed || _target.IsTotalAmmoEmpty()) //已经被销毁, 或者弹药已经被其他角色捡走
{
@@ -96,7 +92,7 @@
else
{
//检测目标没有超出跟随视野距离
- _isInTailAfterRange = Master.IsInTailAfterViewRange(Player.Current.GetCenterPosition());
+ _isInTailAfterRange = Master.IsInTailAfterViewRange(Master.LookTarget.GetCenterPosition());
if (_isInTailAfterRange)
{
_tailAfterTimer = 0;
@@ -143,11 +139,11 @@
if (_tailAfterTimer <= 0)
{
- Master.DrawLine(Vector2.Zero, Master.ToLocal(Player.Current.GetCenterPosition()), Colors.Orange);
+ Master.DrawLine(Vector2.Zero, Master.ToLocal(Master.LookTarget.GetCenterPosition()), Colors.Orange);
}
else if (_tailAfterTimer <= 10)
{
- Master.DrawLine(Vector2.Zero, Master.ToLocal(Player.Current.GetCenterPosition()), Colors.Blue);
+ Master.DrawLine(Vector2.Zero, Master.ToLocal(Master.LookTarget.GetCenterPosition()), Colors.Blue);
}
}
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 30b04ff..6d7f141 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiFollowUpState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiFollowUpState.cs
@@ -1,4 +1,5 @@
+using System;
using Godot;
namespace AdvancedState;
@@ -18,15 +19,15 @@
public override void Enter(AIAdvancedStateEnum prev, params object[] args)
{
+ if (Master.LookTarget == null)
+ {
+ throw new Exception("进入 AIAdvancedStateEnum.AiFollowUp 状态时角色没有攻击目标!");
+ }
+
_navigationUpdateTimer = 0;
Master.TargetInView = true;
}
- public override void Exit(AIAdvancedStateEnum next)
- {
- Master.LookTarget = null;
- }
-
public override void Process(float delta)
{
//先检查弹药是否打光
@@ -46,7 +47,7 @@
}
}
- var playerPos = Player.Current.GetCenterPosition();
+ var playerPos = Master.LookTarget.GetCenterPosition();
//更新玩家位置
if (_navigationUpdateTimer <= 0)
@@ -69,9 +70,6 @@
{
inAttackRange = distanceSquared <= Mathf.Pow(Master.GetWeaponRange(0.7f), 2);
}
-
- //枪口指向玩家
- Master.LookTarget = Player.Current;
if (!Master.NavigationAgent2D.IsNavigationFinished())
{
@@ -121,7 +119,7 @@
public override void DebugDraw()
{
- var playerPos = Player.Current.GetCenterPosition();
+ var playerPos = Master.LookTarget.GetCenterPosition();
Master.DrawLine(new Vector2(0, -8), Master.ToLocal(playerPos), Colors.Red);
}
}
\ No newline at end of file
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 9bdea9c..3383060 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiLeaveForState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiLeaveForState.cs
@@ -1,4 +1,5 @@
+using System;
using Godot;
namespace AdvancedState;
@@ -12,22 +13,26 @@
private float _navigationUpdateTimer = 0;
private float _navigationInterval = 0.3f;
+ //目标
+ private ActivityObject _target;
+ //目标点
+ private Vector2 _targetPosition;
+
public AiLeaveForState() : base(AIAdvancedStateEnum.AiLeaveFor)
{
}
public override void Enter(AIAdvancedStateEnum prev, params object[] args)
{
- if (Master.World.Enemy_IsFindTarget)
+ if (args.Length == 0)
{
- Master.NavigationAgent2D.TargetPosition = Master.World.Enemy_FindTargetPosition;
- }
- else
- {
- ChangeState(prev);
- return;
+ throw new Exception("进入 AINormalStateEnum.AiLeaveFor 状态必须带上目标对象");
}
+ _target = (ActivityObject)args[0];
+ _targetPosition = _target.GetCenterPosition();
+ Master.LookTargetPosition(_targetPosition);
+
//先检查弹药是否打光
if (Master.IsAllWeaponTotalAmmoEmpty())
{
@@ -40,6 +45,16 @@
}
}
+ ///
+ /// 设置移动目标位置
+ ///
+ public void SetTargetPosition(Vector2 target)
+ {
+ _targetPosition = target;
+ _navigationUpdateTimer = _navigationInterval;
+ Master.NavigationAgent2D.TargetPosition = target;
+ }
+
public override void Process(float delta)
{
//这个状态下不会有攻击事件, 所以没必要每一帧检查是否弹药耗尽
@@ -49,7 +64,7 @@
{
//每隔一段时间秒更改目标位置
_navigationUpdateTimer = _navigationInterval;
- Master.NavigationAgent2D.TargetPosition = Master.World.Enemy_FindTargetPosition;
+ Master.NavigationAgent2D.TargetPosition = _targetPosition;
}
else
{
@@ -58,7 +73,7 @@
if (!Master.NavigationAgent2D.IsNavigationFinished())
{
- Master.LookTargetPosition(Master.World.Enemy_FindTargetPosition);
+ Master.LookTargetPosition(_targetPosition);
//移动
Master.DoMove();
}
@@ -77,6 +92,7 @@
//关闭射线检测
Master.TestViewRayCastOver();
//切换成发现目标状态
+ Master.LookTarget = Player.Current;
ChangeState(AIAdvancedStateEnum.AiFollowUp);
return;
}
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 bc57b33..8a4858b 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiNormalState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiNormalState.cs
@@ -8,9 +8,6 @@
///
public class AiNormalState : StateBase
{
- //是否发现玩家
- private bool _isFindPlayer;
-
//下一个运动的坐标
private Vector2 _nextPos;
@@ -38,106 +35,94 @@
public override void Enter(AIAdvancedStateEnum prev, params object[] args)
{
- _isFindPlayer = false;
_isMoveOver = true;
_againstWall = false;
_againstWallNormalAngle = 0;
_pauseTimer = 0;
_moveFlag = false;
+ Master.LookTarget = null;
}
public override void Process(float delta)
{
- //其他敌人发现玩家
- if (Master.CanChangeLeaveFor())
+ //检测玩家
+ var player = Player.Current;
+ //玩家中心点坐标
+ var playerPos = player.GetCenterPosition();
+
+ if (Master.IsInViewRange(playerPos) && !Master.TestViewRayCast(playerPos)) //发现玩家
{
- ChangeState(AIAdvancedStateEnum.AiLeaveFor);
+ //发现玩家
+ Master.LookTarget = player;
+ //进入惊讶状态, 然后再进入通知状态
+ ChangeState(AIAdvancedStateEnum.AiAstonished, AIAdvancedStateEnum.AiNotify);
return;
}
-
- if (_isFindPlayer) //已经找到玩家了
+ else if (_pauseTimer >= 0)
{
- //现临时处理, 直接切换状态
- ChangeState(AIAdvancedStateEnum.AiTailAfter);
+ Master.AnimatedSprite.Play(AnimatorNames.Idle);
+ _pauseTimer -= delta;
}
- else //没有找到玩家
+ else if (_isMoveOver) //没发现玩家, 且已经移动完成
{
- //检测玩家
- var player = Player.Current;
- //玩家中心点坐标
- var playerPos = player.GetCenterPosition();
-
- if (Master.IsInViewRange(playerPos) && !Master.TestViewRayCast(playerPos)) //发现玩家
- {
- //发现玩家
- _isFindPlayer = true;
- }
- else if (_pauseTimer >= 0)
- {
- Master.AnimatedSprite.Play(AnimatorNames.Idle);
- _pauseTimer -= delta;
- }
- else if (_isMoveOver) //没发现玩家, 且已经移动完成
+ RunOver();
+ _isMoveOver = false;
+ }
+ else //移动中
+ {
+ if (_lockTimer >= 1) //卡在一个点超过一秒
{
RunOver();
_isMoveOver = false;
+ _lockTimer = 0;
}
- else //移动中
+ else if (Master.NavigationAgent2D.IsNavigationFinished()) //到达终点
{
- if (_lockTimer >= 1) //卡在一个点超过一秒
+ _pauseTimer = Utils.Random.RandomRangeFloat(0.3f, 2f);
+ _isMoveOver = true;
+ _moveFlag = false;
+ //站立
+ Master.DoIdle();
+ }
+ else if (!_moveFlag)
+ {
+ _moveFlag = true;
+ var pos = Master.Position;
+ //移动
+ Master.DoMove();
+ _prevPos = pos;
+ }
+ else
+ {
+ var pos = Master.Position;
+ var lastSlideCollision = Master.GetLastSlideCollision();
+ if (lastSlideCollision != null && lastSlideCollision.GetCollider() is AdvancedRole) //碰到其他角色
{
- RunOver();
- _isMoveOver = false;
- _lockTimer = 0;
- }
- else if (Master.NavigationAgent2D.IsNavigationFinished()) //到达终点
- {
- _pauseTimer = Utils.Random.RandomRangeFloat(0.3f, 2f);
+ _pauseTimer = Utils.Random.RandomRangeFloat(0.1f, 0.5f);
_isMoveOver = true;
_moveFlag = false;
//站立
Master.DoIdle();
}
- else if (!_moveFlag)
+ else
{
- _moveFlag = true;
- var pos = Master.Position;
//移动
Master.DoMove();
- _prevPos = pos;
+ }
+
+ if (_prevPos.DistanceSquaredTo(pos) <= 0.01f)
+ {
+ _lockTimer += delta;
}
else
{
- var pos = Master.Position;
- var lastSlideCollision = Master.GetLastSlideCollision();
- if (lastSlideCollision != null && lastSlideCollision.GetCollider() is AdvancedRole) //碰到其他角色
- {
- _pauseTimer = Utils.Random.RandomRangeFloat(0.1f, 0.5f);
- _isMoveOver = true;
- _moveFlag = false;
- //站立
- Master.DoIdle();
- }
- else
- {
- //移动
- Master.DoMove();
- }
-
- if (_prevPos.DistanceSquaredTo(pos) <= 0.01f)
- {
- _lockTimer += delta;
- }
- else
- {
- _prevPos = pos;
- }
+ _prevPos = pos;
}
}
-
- //关闭射线检测
- Master.TestViewRayCastOver();
}
+
+ //关闭射线检测
+ Master.TestViewRayCastOver();
}
//移动结束
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiNotifyState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiNotifyState.cs
new file mode 100644
index 0000000..b8fe1fa
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiNotifyState.cs
@@ -0,0 +1,36 @@
+using System;
+
+namespace AdvancedState;
+
+///
+/// 发现目标, 通知其它敌人
+///
+public class AiNotifyState : StateBase
+{
+ private float _timer;
+
+ public AiNotifyState() : base(AIAdvancedStateEnum.AiNotify)
+ {
+ }
+
+ public override void Enter(AIAdvancedStateEnum prev, params object[] args)
+ {
+ if (Master.LookTarget == null)
+ {
+ throw new Exception("进入 AIAdvancedStateEnum.AiNotify 没有攻击目标!");
+ }
+ _timer = 0.6f;
+ //通知其它角色
+ Master.World.NotifyEnemyTarget(Master, Master.LookTarget);
+ }
+
+ public override void Process(float delta)
+ {
+ Master.DoIdle();
+ _timer -= delta;
+ if (_timer <= 0)
+ {
+ ChangeState(AIAdvancedStateEnum.AiTailAfter);
+ }
+ }
+}
\ No newline at end of file
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 2b063e8..6faee7a 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiSurroundState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiSurroundState.cs
@@ -1,4 +1,5 @@
+using System;
using Godot;
namespace AdvancedState;
@@ -29,17 +30,17 @@
public override void Enter(AIAdvancedStateEnum prev, params object[] args)
{
+ if (Master.LookTarget == null)
+ {
+ throw new Exception("进入 AIAdvancedStateEnum.AiSurround 状态时角色没有攻击目标!");
+ }
+
Master.TargetInView = true;
_isMoveOver = true;
_pauseTimer = 0;
_moveFlag = false;
}
- public override void Exit(AIAdvancedStateEnum next)
- {
- Master.LookTarget = null;
- }
-
public override void Process(float delta)
{
//先检查弹药是否打光
@@ -54,12 +55,9 @@
}
}
- var playerPos = Player.Current.GetCenterPosition();
+ var playerPos = Master.LookTarget.GetCenterPosition();
var weapon = Master.WeaponPack.ActiveItem;
- //枪口指向玩家
- Master.LookTarget = Player.Current;
-
//检测玩家是否在视野内
if (Master.IsInTailAfterViewRange(playerPos))
{
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 1146b13..a4bd0f6 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiTailAfterState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/advancedState/AiTailAfterState.cs
@@ -1,10 +1,11 @@
+using System;
using Godot;
namespace AdvancedState;
///
-/// AI 发现玩家, 跟随玩家
+/// AI 发现玩家, 跟随玩家, 但是不在视野范围内
///
public class AiTailAfterState : StateBase
{
@@ -26,6 +27,11 @@
public override void Enter(AIAdvancedStateEnum prev, params object[] args)
{
+ if (Master.LookTarget == null)
+ {
+ throw new Exception("进入 AIAdvancedStateEnum.AiTailAfter 状态时角色没有攻击目标!");
+ }
+
_isInViewRange = true;
_navigationUpdateTimer = 0;
_viewTimer = 0;
@@ -42,16 +48,11 @@
}
}
- public override void Exit(AIAdvancedStateEnum next)
- {
- Master.LookTarget = null;
- }
-
public override void Process(float delta)
{
//这个状态下不会有攻击事件, 所以没必要每一帧检查是否弹药耗尽
- var playerPos = Player.Current.GetCenterPosition();
+ var playerPos = Master.LookTarget.GetCenterPosition();
//更新玩家位置
if (_navigationUpdateTimer <= 0)
@@ -65,9 +66,6 @@
_navigationUpdateTimer -= delta;
}
- //枪口指向玩家
- Master.LookTarget = Player.Current;
-
if (!Master.NavigationAgent2D.IsNavigationFinished())
{
//移动
@@ -117,7 +115,7 @@
public override void DebugDraw()
{
- var playerPos = Player.Current.GetCenterPosition();
+ var playerPos = Master.LookTarget.GetCenterPosition();
if (_isInViewRange)
{
Master.DrawLine(new Vector2(0, -8), Master.ToLocal(playerPos), Colors.Orange);
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AINormalStateEnum.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AINormalStateEnum.cs
index 9b8fe24..35e56dd 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AINormalStateEnum.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AINormalStateEnum.cs
@@ -9,7 +9,11 @@
///
/// 找到玩家,准备通知其他敌人
///
- AiFind,
+ AiNotify,
+ ///
+ /// 发现目标, 惊讶状态
+ ///
+ AiAstonished,
///
/// 收到其他敌人通知, 前往发现目标的位置
///
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiAstonishedState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiAstonishedState.cs
new file mode 100644
index 0000000..74fd553
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiAstonishedState.cs
@@ -0,0 +1,41 @@
+namespace NnormalState;
+
+///
+/// 发现目标时的惊讶状态
+///
+public class AiAstonishedState : StateBase
+{
+ ///
+ /// 下一个状态
+ ///
+ public AINormalStateEnum NextState;
+
+ private float _timer;
+
+ public AiAstonishedState() : base(AINormalStateEnum.AiAstonished)
+ {
+ }
+
+ public override void Enter(AINormalStateEnum prev, params object[] args)
+ {
+ if (args.Length == 0)
+ {
+ Debug.Log("进入 AINormalStateEnum.AiAstonished 状态必传入下一个状态做完参数!");
+ ChangeState(prev);
+ return;
+ }
+
+ NextState = (AINormalStateEnum)args[0];
+ _timer = 1.5f;
+ }
+
+ public override void Process(float delta)
+ {
+ Master.DoIdle();
+ _timer -= delta;
+ if (_timer <= 0)
+ {
+ ChangeState(NextState);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiLeaveForState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiLeaveForState.cs
index 9cd1c49..98163be 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiLeaveForState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiLeaveForState.cs
@@ -18,68 +18,68 @@
public override void Enter(AINormalStateEnum prev, params object[] args)
{
- if (Master.World.Enemy_IsFindTarget)
- {
- Master.NavigationAgent2D.TargetPosition = Master.World.Enemy_FindTargetPosition;
- }
- else
- {
- ChangeState(prev);
- }
+ // if (Master.World.Enemy_IsFindTarget)
+ // {
+ // Master.NavigationAgent2D.TargetPosition = Master.World.Enemy_FindTargetPosition;
+ // }
+ // else
+ // {
+ // ChangeState(prev);
+ // }
}
public override void Process(float delta)
{
- //这个状态下不会有攻击事件, 所以没必要每一帧检查是否弹药耗尽
-
- //更新玩家位置
- if (_navigationUpdateTimer <= 0)
- {
- //每隔一段时间秒更改目标位置
- _navigationUpdateTimer = _navigationInterval;
- Master.NavigationAgent2D.TargetPosition = Master.World.Enemy_FindTargetPosition;
- }
- else
- {
- _navigationUpdateTimer -= delta;
- }
-
- if (!Master.NavigationAgent2D.IsNavigationFinished())
- {
- Master.LookTargetPosition(Master.World.Enemy_FindTargetPosition);
- //移动
- Master.DoMove();
- }
- else
- {
- //站立
- Master.DoIdle();
- }
-
- var playerPos = Player.Current.GetCenterPosition();
- //检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态
- if (Master.IsInTailAfterViewRange(playerPos))
- {
- if (!Master.TestViewRayCast(playerPos)) //看到玩家
- {
- //关闭射线检测
- Master.TestViewRayCastOver();
- //切换成发现目标状态
- ChangeState(AINormalStateEnum.AiFollowUp);
- return;
- }
- else
- {
- //关闭射线检测
- Master.TestViewRayCastOver();
- }
- }
-
- //移动到目标掉了, 还没发现目标
- if (Master.NavigationAgent2D.IsNavigationFinished())
- {
- ChangeState(AINormalStateEnum.AiNormal);
- }
+ // //这个状态下不会有攻击事件, 所以没必要每一帧检查是否弹药耗尽
+ //
+ // //更新玩家位置
+ // if (_navigationUpdateTimer <= 0)
+ // {
+ // //每隔一段时间秒更改目标位置
+ // _navigationUpdateTimer = _navigationInterval;
+ // Master.NavigationAgent2D.TargetPosition = Master.World.Enemy_FindTargetPosition;
+ // }
+ // else
+ // {
+ // _navigationUpdateTimer -= delta;
+ // }
+ //
+ // if (!Master.NavigationAgent2D.IsNavigationFinished())
+ // {
+ // Master.LookTargetPosition(Master.World.Enemy_FindTargetPosition);
+ // //移动
+ // Master.DoMove();
+ // }
+ // else
+ // {
+ // //站立
+ // Master.DoIdle();
+ // }
+ //
+ // var playerPos = Player.Current.GetCenterPosition();
+ // //检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态
+ // if (Master.IsInTailAfterViewRange(playerPos))
+ // {
+ // if (!Master.TestViewRayCast(playerPos)) //看到玩家
+ // {
+ // //关闭射线检测
+ // Master.TestViewRayCastOver();
+ // //切换成发现目标状态
+ // ChangeState(AINormalStateEnum.AiFollowUp);
+ // return;
+ // }
+ // else
+ // {
+ // //关闭射线检测
+ // Master.TestViewRayCastOver();
+ // }
+ // }
+ //
+ // //移动到目标掉了, 还没发现目标
+ // if (Master.NavigationAgent2D.IsNavigationFinished())
+ // {
+ // ChangeState(AINormalStateEnum.AiNormal);
+ // }
}
public override void DebugDraw()
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 c2f2a32..61469b8 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiNormalState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiNormalState.cs
@@ -47,13 +47,6 @@
public override void Process(float delta)
{
- //其他敌人发现玩家
- if (Master.CanChangeLeaveFor())
- {
- ChangeState(AINormalStateEnum.AiLeaveFor);
- return;
- }
-
if (_isFindPlayer) //已经找到玩家了
{
//现临时处理, 直接切换状态
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiNotifyState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiNotifyState.cs
new file mode 100644
index 0000000..76e46c4
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AiNotifyState.cs
@@ -0,0 +1,30 @@
+namespace NnormalState;
+
+///
+/// 发现目标, 通知其它敌人
+///
+public class AiNotifyState : StateBase
+{
+
+ private float _timer;
+
+ public AiNotifyState() : base(AINormalStateEnum.AiNotify)
+ {
+ }
+
+ public override void Enter(AINormalStateEnum prev, params object[] args)
+ {
+ _timer = 1.5f;
+ //通知其它角色
+ Master.World.NotifyEnemyTarget(Master, Player.Current);
+ }
+
+ public override void Process(float delta)
+ {
+ _timer -= delta;
+ if (_timer <= 0)
+ {
+ ChangeState(AINormalStateEnum.AiTailAfter);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs
index d92e804..40e84e3 100644
--- a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs
@@ -183,14 +183,14 @@
{
//Hurt(1000, 0);
Hp = 0;
- Hurt(1000, 0);
+ Hurt(this, 1000, 0);
}
else if (Input.IsKeyPressed(Key.O)) //测试用, 消灭房间内所有敌人
{
var enemyList = AffiliationArea.FindIncludeItems(o => o.CollisionWithMask(PhysicsLayer.Enemy));
foreach (var enemy in enemyList)
{
- ((AdvancedEnemy)enemy).Hurt(1000, 0);
+ ((AdvancedEnemy)enemy).Hurt(this, 1000, 0);
}
}
// //测试用
@@ -224,7 +224,7 @@
return 1;
}
- protected override void OnHit(int damage, bool realHarm)
+ protected override void OnHit(ActivityObject target, int damage, bool realHarm)
{
//进入无敌状态
if (realHarm) //真实伤害
diff --git a/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs b/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs
index de74723..b5db0d6 100644
--- a/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs
+++ b/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs
@@ -159,7 +159,7 @@
}
//造成伤害
- role.CallDeferred(nameof(AdvancedRole.Hurt), damage, (role.GetCenterPosition() - GlobalPosition).Angle());
+ role.CallDeferred(nameof(AdvancedRole.Hurt), TriggerRole, damage, (role.GetCenterPosition() - GlobalPosition).Angle());
}
else if (activityObject is Bullet bullet) //攻击子弹
{
diff --git a/DungeonShooting_Godot/src/game/room/World.cs b/DungeonShooting_Godot/src/game/room/World.cs
index 27d4805..580c809 100644
--- a/DungeonShooting_Godot/src/game/room/World.cs
+++ b/DungeonShooting_Godot/src/game/room/World.cs
@@ -65,21 +65,6 @@
///
public List Enemy_InstanceList { get; } = new List();
- // ///
- // /// 公共属性, 敌人是否找到目标, 如果找到目标, 则与目标同房间的所有敌人都会知道目标的位置
- // ///
- // public bool Enemy_IsFindTarget { get; set; }
- //
- // ///
- // /// 公共属性, 敌人在哪个区域找到的目标, 所有该区域下的敌人都会知道目标的位置
- // ///
- // public HashSet Enemy_FindTargetAffiliationSet { get; } = new HashSet();
- //
- // ///
- // /// 公共属性, 敌人找到的目标的位置, 如果目标在视野内, 则一直更新
- // ///
- // public Vector2 Enemy_FindTargetPosition { get; set; }
-
private bool _pause = false;
private List _coroutineList;
@@ -131,9 +116,10 @@
if (role is AdvancedEnemy advancedEnemy)
{
//将未发现目标的敌人状态置为惊讶状态
- if (advancedEnemy.StateController.CurrState == AIAdvancedStateEnum.AiNormal)
+ var controller = advancedEnemy.StateController;
+ if (controller.CurrState == AIAdvancedStateEnum.AiNormal)
{
- advancedEnemy.StateController.ChangeState(AIAdvancedStateEnum.AiAstonished);
+ controller.ChangeState(AIAdvancedStateEnum.AiAstonished, AIAdvancedStateEnum.AiLeaveFor, target);
}
}
}