Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / role / enemy / state / AiNormalState.cs
@小李xl 小李xl on 22 Nov 2023 5 KB 完善ai状态机
  1.  
  2. using System.Linq;
  3. using Godot;
  4.  
  5. namespace EnemyState;
  6.  
  7. /// <summary>
  8. /// AI 正常状态
  9. /// </summary>
  10. public class AiNormalState : StateBase<Enemy, AIStateEnum>
  11. {
  12. //下一个运动的坐标
  13. private Vector2 _nextPos;
  14.  
  15. //是否移动结束
  16. private bool _isMoveOver;
  17.  
  18. //上一次移动是否撞墙
  19. private bool _againstWall;
  20. //撞墙法线角度
  21. private float _againstWallNormalAngle;
  22.  
  23. //移动停顿计时器
  24. private float _pauseTimer;
  25. private bool _moveFlag;
  26.  
  27. //上一帧位置
  28. private Vector2 _prevPos;
  29. //卡在一个位置的时间
  30. private float _lockTimer;
  31.  
  32. public AiNormalState() : base(AIStateEnum.AiNormal)
  33. {
  34. }
  35.  
  36. public override void Enter(AIStateEnum prev, params object[] args)
  37. {
  38. _isMoveOver = true;
  39. _againstWall = false;
  40. _againstWallNormalAngle = 0;
  41. _pauseTimer = 0;
  42. _moveFlag = false;
  43. Master.LookTarget = null;
  44. }
  45.  
  46. public override void Process(float delta)
  47. {
  48. //检测玩家
  49. var player = Player.Current;
  50. //玩家中心点坐标
  51. var playerPos = player.GetCenterPosition();
  52.  
  53. if (Master.IsInViewRange(playerPos) && !Master.TestViewRayCast(playerPos)) //发现玩家
  54. {
  55. //关闭射线检测
  56. Master.TestViewRayCastOver();
  57. //发现玩家
  58. Master.LookTarget = player;
  59. //判断是否进入通知状态
  60. if (Master.World.Enemy_InstanceList.FindIndex(enemy =>
  61. enemy != Master && !enemy.IsDie && enemy.AffiliationArea == Master.AffiliationArea &&
  62. enemy.StateController.CurrState == AIStateEnum.AiNormal) != -1)
  63. {
  64. //进入惊讶状态, 然后再进入通知状态
  65. ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiNotify);
  66. }
  67. else
  68. {
  69. //进入惊讶状态, 然后再进入跟随状态
  70. ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiTailAfter);
  71. }
  72. return;
  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. //站立
  98. Master.DoIdle();
  99. }
  100. else if (!_moveFlag)
  101. {
  102. _moveFlag = true;
  103. var pos = Master.Position;
  104. //移动
  105. Master.DoMove();
  106. _prevPos = pos;
  107. }
  108. else
  109. {
  110. var pos = Master.Position;
  111. var lastSlideCollision = Master.GetLastSlideCollision();
  112. if (lastSlideCollision != null && lastSlideCollision.GetCollider() is Role) //碰到其他角色
  113. {
  114. _pauseTimer = Utils.Random.RandomRangeFloat(0.1f, 0.5f);
  115. _isMoveOver = true;
  116. _moveFlag = false;
  117. //站立
  118. Master.DoIdle();
  119. }
  120. else
  121. {
  122. //移动
  123. Master.DoMove();
  124. }
  125.  
  126. if (_prevPos.DistanceSquaredTo(pos) <= 0.01f)
  127. {
  128. _lockTimer += delta;
  129. }
  130. else
  131. {
  132. _prevPos = pos;
  133. }
  134. }
  135. }
  136.  
  137. //关闭射线检测
  138. Master.TestViewRayCastOver();
  139. }
  140.  
  141. //移动结束
  142. private void RunOver()
  143. {
  144. float angle;
  145. if (_againstWall)
  146. {
  147. angle = Utils.Random.RandomRangeFloat(_againstWallNormalAngle - Mathf.Pi * 0.5f,
  148. _againstWallNormalAngle + Mathf.Pi * 0.5f);
  149. }
  150. else
  151. {
  152. angle = Utils.Random.RandomRangeFloat(0, Mathf.Pi * 2f);
  153. }
  154.  
  155. var len = Utils.Random.RandomRangeInt(30, 200);
  156. _nextPos = new Vector2(len, 0).Rotated(angle) + Master.GlobalPosition;
  157. //获取射线碰到的坐标
  158. if (Master.TestViewRayCast(_nextPos)) //碰到墙壁
  159. {
  160. _nextPos = Master.ViewRay.GetCollisionPoint();
  161. _againstWall = true;
  162. _againstWallNormalAngle = Master.ViewRay.GetCollisionNormal().Angle();
  163. }
  164. else
  165. {
  166. _againstWall = false;
  167. }
  168.  
  169. Master.NavigationAgent2D.TargetPosition = _nextPos;
  170. Master.LookTargetPosition(_nextPos);
  171. }
  172.  
  173. public override void DebugDraw()
  174. {
  175. Master.DrawLine(new Vector2(0, -8), Master.ToLocal(_nextPos), Colors.Green);
  176. }
  177. }