diff --git a/DungeonShooting_Godot/src/game/role/IState.cs b/DungeonShooting_Godot/src/game/role/IState.cs
deleted file mode 100644
index 0a7c2b0..0000000
--- a/DungeonShooting_Godot/src/game/role/IState.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using System;///
-/// 状态接口
-///
-public interface IState where T : ActivityObject where S : Enum
-{
- ///
- /// 当前状态对象对应的状态枚举类型
- ///
- S StateType { get; }
-
- ///
- /// 当前状态对象挂载的角色对象
- ///
- T Master { get; set; }
-
- ///
- /// 当前状态对象所处的状态机对象
- ///
- StateController StateController { get; set; }
-
- ///
- /// 当从其他状态进入到当前状态时调用
- ///
- /// 上一个状态类型
- /// 切换当前状态时附带的参数
- void Enter(S prev, params object[] args);
-
- ///
- /// 物理帧每帧更新
- ///
- void PhysicsProcess(float delta);
-
- ///
- /// 是否允许切换至下一个状态
- ///
- /// 下一个状态类型
- bool CanChangeState(S next);
-
- ///
- /// 从当前状态退出时调用
- ///
- /// 下一个状态类型
- void Exit(S next);
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/StateBase.cs b/DungeonShooting_Godot/src/game/role/StateBase.cs
new file mode 100644
index 0000000..531f049
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/role/StateBase.cs
@@ -0,0 +1,63 @@
+using System;
+
+///
+/// 状态基类
+///
+public abstract class StateBase where T : ActivityObject where S : Enum
+{
+ ///
+ /// 当前状态对象对应的状态枚举类型
+ ///
+ public S StateType { get; }
+
+ ///
+ /// 当前状态对象挂载的角色对象
+ ///
+ public T Master { get; set; }
+
+ ///
+ /// 当前状态对象所处的状态机对象
+ ///
+ public StateController StateController { get; set; }
+
+ public StateBase(S state)
+ {
+ StateType = state;
+ }
+
+ ///
+ /// 当从其他状态进入到当前状态时调用
+ ///
+ /// 上一个状态类型
+ /// 切换当前状态时附带的参数
+ public virtual void Enter(S prev, params object[] args)
+ {
+
+ }
+
+ ///
+ /// 物理帧每帧更新
+ ///
+ public virtual void PhysicsProcess(float delta)
+ {
+
+ }
+
+ ///
+ /// 是否允许切换至下一个状态
+ ///
+ /// 下一个状态类型
+ public virtual bool CanChangeState(S next)
+ {
+ return true;
+ }
+
+ ///
+ /// 从当前状态退出时调用
+ ///
+ /// 下一个状态类型
+ public virtual void Exit(S next)
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/StateController.cs b/DungeonShooting_Godot/src/game/role/StateController.cs
index 18943c0..ad9557d 100644
--- a/DungeonShooting_Godot/src/game/role/StateController.cs
+++ b/DungeonShooting_Godot/src/game/role/StateController.cs
@@ -10,13 +10,13 @@
///
/// 当前活跃的状态
///
- public IState CurrState => _currState;
- private IState _currState;
+ public StateBase CurrStateBase => _currStateBase;
+ private StateBase _currStateBase;
///
/// 负责存放状态实例对象
///
- private readonly Dictionary> _states = new Dictionary>();
+ private readonly Dictionary> _states = new Dictionary>();
///
/// 记录下当前帧是否有改变的状态
@@ -26,9 +26,9 @@
public override void PhysicsProcess(float delta)
{
_isChangeState = false;
- if (CurrState != null)
+ if (CurrStateBase != null)
{
- CurrState.PhysicsProcess(delta);
+ CurrStateBase.PhysicsProcess(delta);
//判断当前帧是否有改变的状态, 如果有, 则重新调用 PhysicsProcess() 方法
if (_isChangeState)
{
@@ -40,16 +40,16 @@
///
/// 往状态机力注册一个新的状态
///
- public void Register(IState state)
+ public void Register(StateBase stateBase)
{
- if (GetStateInstance(state.StateType) != null)
+ if (GetStateInstance(stateBase.StateType) != null)
{
- GD.PrintErr("当前状态已经在状态机中注册:", state);
+ GD.PrintErr("当前状态已经在状态机中注册:", stateBase);
return;
}
- state.Master = ActivityObject as T;
- state.StateController = this;
- _states.Add(state.StateType, state);
+ stateBase.Master = ActivityObject as T;
+ stateBase.StateController = this;
+ _states.Add(stateBase.StateType, stateBase);
}
///
@@ -71,7 +71,7 @@
///
/// 根据状态类型获取相应的状态对象
///
- private IState GetStateInstance(S stateType)
+ private StateBase GetStateInstance(S stateType)
{
_states.TryGetValue(stateType, out var v);
return v;
@@ -82,7 +82,7 @@
///
private void _changeState(bool late, S next, params object[] arg)
{
- if (_currState != null && _currState.StateType.Equals(next))
+ if (_currStateBase != null && _currStateBase.StateType.Equals(next))
{
return;
}
@@ -92,19 +92,19 @@
GD.PrintErr("当前状态机未找到相应状态:" + next);
return;
}
- if (_currState == null)
+ if (_currStateBase == null)
{
- _currState = newState;
+ _currStateBase = newState;
newState.Enter(default, arg);
}
- else if (_currState.CanChangeState(next))
+ else if (_currStateBase.CanChangeState(next))
{
_isChangeState = !late;
- var prev = _currState.StateType;
- _currState.Exit(next);
+ var prev = _currStateBase.StateType;
+ _currStateBase.Exit(next);
GD.Print("nextState => " + next);
- _currState = newState;
- _currState.Enter(prev, arg);
+ _currStateBase = newState;
+ _currStateBase.Enter(prev, arg);
}
}
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
index 6e3eaa8..6d30caa 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
@@ -38,10 +38,16 @@
/// 视野检测射线, 朝玩家打射线, 检测是否碰到墙
///
public RayCast2D ViewRay { get; }
+
+ ///
+ /// 导航代理
+ ///
+ public NavigationAgent2D NavigationAgent2D { get; }
- private Position2D _navigationPoint;
- private NavigationAgent2D _navigationAgent2D;
- private float _navigationUpdateTimer = 0;
+ ///
+ /// 导航代理中点
+ ///
+ public Position2D NavigationPoint { get; }
public Enemy() : base(ResourcePath.prefab_role_Enemy_tscn)
{
@@ -58,15 +64,15 @@
//视野射线
ViewRay = GetNode("ViewRay");
- _navigationPoint = GetNode("NavigationPoint");
- _navigationAgent2D = _navigationPoint.GetNode("NavigationAgent2D");
+ NavigationPoint = GetNode("NavigationPoint");
+ NavigationAgent2D = NavigationPoint.GetNode("NavigationAgent2D");
//PathSign = new PathSign(this, PathSignLength, GameApplication.Instance.Room.Player);
//注册Ai状态机
- StateController.Register(new AINormalState());
- StateController.Register(new AIProbeState());
- StateController.Register(new AITailAfterState());
+ StateController.Register(new AiNormalStateBase());
+ StateController.Register(new AiProbeStateBase());
+ StateController.Register(new AiTailAfterStateBase());
}
public override void _Ready()
@@ -75,7 +81,7 @@
//默认状态
StateController.ChangeState(AIStateEnum.AINormal);
- _navigationAgent2D.SetTargetLocation(GameApplication.Instance.Room.Player.GlobalPosition);
+ NavigationAgent2D.SetTargetLocation(GameApplication.Instance.Room.Player.GlobalPosition);
}
///
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AINormalState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AINormalState.cs
deleted file mode 100644
index 45b13c2..0000000
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AINormalState.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-
-using Godot;
-
-///
-/// AI 正常状态
-///
-public class AINormalState : IState
-{
- public AIStateEnum StateType { get; } = AIStateEnum.AINormal;
- public Enemy Master { get; set; }
- public StateController StateController { get; set; }
- public void Enter(AIStateEnum prev, params object[] args)
- {
-
- }
-
- public void PhysicsProcess(float delta)
- {
- //检测玩家
- var player = GameApplication.Instance.Room.Player;
- //玩家中心点坐标
- var playerPos = player.MountPoint.GlobalPosition;
-
- if (Master.IsInViewRange(playerPos) && Master.TestViewRayCast(playerPos) == null)
- {
- //发现玩家
- StateController.ChangeStateLate(AIStateEnum.AITailAfter);
- }
- }
-
- public bool CanChangeState(AIStateEnum next)
- {
- return true;
- }
-
- public void Exit(AIStateEnum next)
- {
-
- }
-}
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AIProbeState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AIProbeState.cs
deleted file mode 100644
index 368947d..0000000
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AIProbeState.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-
-///
-/// Ai 不确定玩家位置
-///
-public class AIProbeState : IState
-{
- public AIStateEnum StateType { get; } = AIStateEnum.AIProbe;
- public Enemy Master { get; set; }
- public StateController StateController { get; set; }
- public void Enter(AIStateEnum prev, params object[] args)
- {
-
- }
-
- public void PhysicsProcess(float delta)
- {
-
- }
-
- public bool CanChangeState(AIStateEnum next)
- {
- return true;
- }
-
- public void Exit(AIStateEnum next)
- {
-
- }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AITailAfterState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AITailAfterState.cs
deleted file mode 100644
index 0c1417e..0000000
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AITailAfterState.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-
-///
-/// AI 发现玩家
-///
-public class AITailAfterState : IState
-{
- public AIStateEnum StateType { get; } = AIStateEnum.AITailAfter;
- public Enemy Master { get; set; }
- public StateController StateController { get; set; }
- public void Enter(AIStateEnum prev, params object[] args)
- {
-
- }
-
- public void PhysicsProcess(float delta)
- {
-
- }
-
- public bool CanChangeState(AIStateEnum next)
- {
- return true;
- }
-
- public void Exit(AIStateEnum next)
- {
-
- }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalStateBase.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalStateBase.cs
new file mode 100644
index 0000000..65a3148
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalStateBase.cs
@@ -0,0 +1,26 @@
+
+using Godot;
+
+///
+/// AI 正常状态
+///
+public class AiNormalStateBase : StateBase
+{
+ public AiNormalStateBase() : base(AIStateEnum.AINormal)
+ {
+ }
+
+ public override void PhysicsProcess(float delta)
+ {
+ //检测玩家
+ var player = GameApplication.Instance.Room.Player;
+ //玩家中心点坐标
+ var playerPos = player.MountPoint.GlobalPosition;
+
+ if (Master.IsInViewRange(playerPos) && Master.TestViewRayCast(playerPos) == null)
+ {
+ //发现玩家
+ StateController.ChangeStateLate(AIStateEnum.AITailAfter);
+ }
+ }
+}
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiProbeStateBase.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiProbeStateBase.cs
new file mode 100644
index 0000000..be9854d
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiProbeStateBase.cs
@@ -0,0 +1,10 @@
+
+///
+/// Ai 不确定玩家位置
+///
+public class AiProbeStateBase : StateBase
+{
+ public AiProbeStateBase() : base(AIStateEnum.AIProbe)
+ {
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterStateBase.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterStateBase.cs
new file mode 100644
index 0000000..725bf8e
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterStateBase.cs
@@ -0,0 +1,43 @@
+
+///
+/// AI 发现玩家
+///
+public class AiTailAfterStateBase : StateBase
+{
+
+ private float _navigationUpdateTimer = 0;
+
+ public AiTailAfterStateBase() : base(AIStateEnum.AITailAfter)
+ {
+ }
+
+ public override void PhysicsProcess(float delta)
+ {
+ //跟随玩家
+ var master = Master;
+ if (master.NavigationAgent2D.IsNavigationFinished())
+ {
+ return;
+ }
+ var playerGlobalPosition = GameApplication.Instance.Room.Player.GlobalPosition;
+ //临时处理, 让敌人跟随玩家
+ if (_navigationUpdateTimer <= 0)
+ {
+ _navigationUpdateTimer = 0.2f;
+ if (master.NavigationAgent2D.GetTargetLocation() != playerGlobalPosition)
+ {
+ master.NavigationAgent2D.SetTargetLocation(playerGlobalPosition);
+ }
+ }
+ else
+ {
+ _navigationUpdateTimer -= delta;
+ }
+
+ var nextPos = master.NavigationAgent2D.GetNextLocation();
+ master.LookTargetPosition(playerGlobalPosition);
+ master.AnimatedSprite.Animation = AnimatorNames.Run;
+ master.Velocity = (nextPos - master.GlobalPosition - master.NavigationPoint.Position).Normalized() * master.MoveSpeed;
+ master.CalcMove(delta);
+ }
+}
\ No newline at end of file