Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / role / ai / state / AiNormalState.cs
  1.  
  2. using System.Linq;
  3. using Godot;
  4.  
  5. namespace AiState;
  6.  
  7. /// <summary>
  8. /// AI 正常状态
  9. /// </summary>
  10. public class AiNormalState : StateBase<AiRole, 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. if (Master.HasAttackDesire) //有攻击欲望
  49. {
  50. //获取攻击目标
  51. var attackTarget = Master.GetAttackTarget(false);
  52. if (attackTarget != null)
  53. {
  54. //发现玩家
  55. Master.LookTarget = attackTarget;
  56. //判断是否进入通知状态
  57. if (Master.World.Role_InstanceList.FindIndex(role =>
  58. role is AiRole enemy &&
  59. enemy != Master && !enemy.IsDie && enemy.AffiliationArea == Master.AffiliationArea &&
  60. enemy.StateController.CurrState == AIStateEnum.AiNormal) != -1)
  61. {
  62. //进入惊讶状态, 然后再进入通知状态
  63. ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiNotify);
  64. }
  65. else
  66. {
  67. //进入惊讶状态, 然后再进入跟随状态
  68. ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiTailAfter);
  69. }
  70.  
  71. return;
  72. }
  73. }
  74.  
  75. if (_pauseTimer >= 0)
  76. {
  77. Master.AnimatedSprite.Play(AnimatorNames.Idle);
  78. _pauseTimer -= delta;
  79. }
  80. else if (_isMoveOver) //没发现玩家, 且已经移动完成
  81. {
  82. RunOver();
  83. _isMoveOver = false;
  84. }
  85. else if (Master.HasMoveDesire) //移动中
  86. {
  87. if (_lockTimer >= 1) //卡在一个点超过一秒
  88. {
  89. RunOver();
  90. _isMoveOver = false;
  91. _lockTimer = 0;
  92. }
  93. else if (Master.NavigationAgent2D.IsNavigationFinished()) //到达终点
  94. {
  95. _pauseTimer = Utils.Random.RandomRangeFloat(0.3f, 2f);
  96. _isMoveOver = true;
  97. _moveFlag = false;
  98. //站立
  99. Master.DoIdle();
  100. }
  101. else if (!_moveFlag)
  102. {
  103. _moveFlag = true;
  104. var pos = Master.Position;
  105. //移动
  106. Master.DoMove();
  107. _prevPos = pos;
  108. }
  109. else
  110. {
  111. var pos = Master.Position;
  112. var lastSlideCollision = Master.GetLastSlideCollision();
  113. if (lastSlideCollision != null && lastSlideCollision.GetCollider() is Role) //碰到其他角色
  114. {
  115. _pauseTimer = Utils.Random.RandomRangeFloat(0.1f, 0.5f);
  116. _isMoveOver = true;
  117. _moveFlag = false;
  118. //站立
  119. Master.DoIdle();
  120. }
  121. else
  122. {
  123. //移动
  124. Master.DoMove();
  125. }
  126.  
  127. if (_prevPos.DistanceSquaredTo(pos) <= 0.01f)
  128. {
  129. _lockTimer += delta;
  130. }
  131. else
  132. {
  133. _prevPos = pos;
  134. }
  135. }
  136. }
  137.  
  138. //关闭射线检测
  139. Master.TestViewRayCastOver();
  140. }
  141.  
  142. //移动结束
  143. private void RunOver()
  144. {
  145. float angle;
  146. if (_againstWall)
  147. {
  148. angle = Utils.Random.RandomRangeFloat(_againstWallNormalAngle - Mathf.Pi * 0.5f,
  149. _againstWallNormalAngle + Mathf.Pi * 0.5f);
  150. }
  151. else
  152. {
  153. angle = Utils.Random.RandomRangeFloat(0, Mathf.Pi * 2f);
  154. }
  155.  
  156. var len = Utils.Random.RandomRangeInt(30, 200);
  157. _nextPos = new Vector2(len, 0).Rotated(angle) + Master.GlobalPosition;
  158. //获取射线碰到的坐标
  159. if (Master.TestViewRayCast(_nextPos)) //碰到墙壁
  160. {
  161. _nextPos = Master.ViewRay.GetCollisionPoint();
  162. _againstWall = true;
  163. _againstWallNormalAngle = Master.ViewRay.GetCollisionNormal().Angle();
  164. }
  165. else
  166. {
  167. _againstWall = false;
  168. }
  169.  
  170. Master.NavigationAgent2D.TargetPosition = _nextPos;
  171. Master.LookTargetPosition(_nextPos);
  172. }
  173.  
  174. public override void DebugDraw()
  175. {
  176. Master.DrawLine(new Vector2(0, -8), Master.ToLocal(_nextPos), Colors.Green);
  177. }
  178. }