Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / role / enemy / advancedState / AiNormalState.cs
@小李xl 小李xl on 10 Nov 2023 5 KB 制作Enemy状态机
  1.  
  2. using Godot;
  3.  
  4. namespace AdvancedState;
  5.  
  6. /// <summary>
  7. /// AI 正常状态
  8. /// </summary>
  9. public class AiNormalState : StateBase<AdvancedEnemy, AiStateEnum>
  10. {
  11. //是否发现玩家
  12. private bool _isFindPlayer;
  13.  
  14. //下一个运动的坐标
  15. private Vector2 _nextPos;
  16.  
  17. //是否移动结束
  18. private bool _isMoveOver;
  19.  
  20. //上一次移动是否撞墙
  21. private bool _againstWall;
  22. //撞墙法线角度
  23. private float _againstWallNormalAngle;
  24.  
  25. //移动停顿计时器
  26. private float _pauseTimer;
  27. private bool _moveFlag;
  28.  
  29. //上一帧位置
  30. private Vector2 _prevPos;
  31. //卡在一个位置的时间
  32. private float _lockTimer;
  33.  
  34. public AiNormalState() : base(AiStateEnum.AiNormal)
  35. {
  36. }
  37.  
  38. public override void Enter(AiStateEnum prev, params object[] args)
  39. {
  40. _isFindPlayer = false;
  41. _isMoveOver = true;
  42. _againstWall = false;
  43. _againstWallNormalAngle = 0;
  44. _pauseTimer = 0;
  45. _moveFlag = false;
  46. }
  47.  
  48. public override void Process(float delta)
  49. {
  50. //其他敌人发现玩家
  51. if (Master.CanChangeLeaveFor())
  52. {
  53. ChangeState(AiStateEnum.AiLeaveFor);
  54. return;
  55. }
  56.  
  57. if (_isFindPlayer) //已经找到玩家了
  58. {
  59. //现临时处理, 直接切换状态
  60. ChangeState(AiStateEnum.AiTailAfter);
  61. }
  62. else //没有找到玩家
  63. {
  64. //检测玩家
  65. var player = Player.Current;
  66. //玩家中心点坐标
  67. var playerPos = player.GetCenterPosition();
  68.  
  69. if (Master.IsInViewRange(playerPos) && !Master.TestViewRayCast(playerPos)) //发现玩家
  70. {
  71. //发现玩家
  72. _isFindPlayer = true;
  73. }
  74. else if (_pauseTimer >= 0)
  75. {
  76. Master.AnimatedSprite.Play(AnimatorNames.Idle);
  77. _pauseTimer -= delta;
  78. }
  79. else if (_isMoveOver) //没发现玩家, 且已经移动完成
  80. {
  81. RunOver();
  82. _isMoveOver = false;
  83. }
  84. else //移动中
  85. {
  86. if (_lockTimer >= 1) //卡在一个点超过一秒
  87. {
  88. RunOver();
  89. _isMoveOver = false;
  90. _lockTimer = 0;
  91. }
  92. else if (Master.NavigationAgent2D.IsNavigationFinished()) //到达终点
  93. {
  94. _pauseTimer = Utils.Random.RandomRangeFloat(0.3f, 2f);
  95. _isMoveOver = true;
  96. _moveFlag = false;
  97. Master.BasisVelocity = Vector2.Zero;
  98. }
  99. else if (!_moveFlag)
  100. {
  101. _moveFlag = true;
  102. var pos = Master.GlobalPosition;
  103. //计算移动
  104. var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
  105. Master.AnimatedSprite.Play(AnimatorNames.Run);
  106. Master.BasisVelocity = (nextPos - pos - Master.NavigationPoint.Position).Normalized() *
  107. Master.RoleState.MoveSpeed;
  108. _prevPos = pos;
  109. }
  110. else
  111. {
  112. var pos = Master.GlobalPosition;
  113. var lastSlideCollision = Master.GetLastSlideCollision();
  114. if (lastSlideCollision != null && lastSlideCollision.GetCollider() is AdvancedRole) //碰到其他角色
  115. {
  116. _pauseTimer = Utils.Random.RandomRangeFloat(0.1f, 0.5f);
  117. _isMoveOver = true;
  118. _moveFlag = false;
  119. Master.BasisVelocity = Vector2.Zero;
  120. }
  121. else
  122. {
  123. //计算移动
  124. var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
  125. Master.AnimatedSprite.Play(AnimatorNames.Run);
  126. Master.BasisVelocity = (nextPos - pos - Master.NavigationPoint.Position).Normalized() *
  127. Master.RoleState.MoveSpeed;
  128. }
  129.  
  130. if (_prevPos.DistanceSquaredTo(pos) <= 0.01f)
  131. {
  132. _lockTimer += delta;
  133. }
  134. else
  135. {
  136. _prevPos = pos;
  137. }
  138. }
  139. }
  140.  
  141. //关闭射线检测
  142. Master.TestViewRayCastOver();
  143. }
  144. }
  145.  
  146. //移动结束
  147. private void RunOver()
  148. {
  149. float angle;
  150. if (_againstWall)
  151. {
  152. angle = Utils.Random.RandomRangeFloat(_againstWallNormalAngle - Mathf.Pi * 0.5f,
  153. _againstWallNormalAngle + Mathf.Pi * 0.5f);
  154. }
  155. else
  156. {
  157. angle = Utils.Random.RandomRangeFloat(0, Mathf.Pi * 2f);
  158. }
  159.  
  160. var len = Utils.Random.RandomRangeInt(30, 200);
  161. _nextPos = new Vector2(len, 0).Rotated(angle) + Master.GlobalPosition;
  162. //获取射线碰到的坐标
  163. if (Master.TestViewRayCast(_nextPos)) //碰到墙壁
  164. {
  165. _nextPos = Master.ViewRay.GetCollisionPoint();
  166. _againstWall = true;
  167. _againstWallNormalAngle = Master.ViewRay.GetCollisionNormal().Angle();
  168. }
  169. else
  170. {
  171. _againstWall = false;
  172. }
  173.  
  174. Master.NavigationAgent2D.TargetPosition = _nextPos;
  175. Master.LookTargetPosition(_nextPos);
  176. }
  177.  
  178. public override void DebugDraw()
  179. {
  180. Master.DrawLine(new Vector2(0, -8), Master.ToLocal(_nextPos), Colors.Green);
  181. }
  182. }