Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / role / enemy / state / AiTailAfterState.cs
  1.  
  2. using System;
  3. using Godot;
  4.  
  5. namespace EnemyState;
  6.  
  7. /// <summary>
  8. /// AI 发现玩家, 跟随玩家, 但是不在视野范围内
  9. /// </summary>
  10. public class AiTailAfterState : StateBase<Enemy, AIStateEnum>
  11. {
  12. /// <summary>
  13. /// 目标是否在视野半径内
  14. /// </summary>
  15. private bool _isInViewRange;
  16.  
  17. //导航目标点刷新计时器
  18. private float _navigationUpdateTimer = 0;
  19. private float _navigationInterval = 0.3f;
  20.  
  21. //目标从视野消失时已经过去的时间
  22. private float _viewTimer;
  23.  
  24. public AiTailAfterState() : base(AIStateEnum.AiTailAfter)
  25. {
  26. }
  27.  
  28. public override void Enter(AIStateEnum prev, params object[] args)
  29. {
  30. if (Master.LookTarget == null)
  31. {
  32. throw new Exception("进入 AIAdvancedStateEnum.AiTailAfter 状态时角色没有攻击目标!");
  33. }
  34. _isInViewRange = true;
  35. _navigationUpdateTimer = 0;
  36. _viewTimer = 0;
  37. //先检查弹药是否打光
  38. if (Master.IsAllWeaponTotalAmmoEmpty())
  39. {
  40. //再寻找是否有可用的武器
  41. var targetWeapon = Master.FindTargetWeapon();
  42. if (targetWeapon != null)
  43. {
  44. ChangeState(AIStateEnum.AiFindAmmo, targetWeapon);
  45. }
  46. }
  47. }
  48.  
  49. public override void Process(float delta)
  50. {
  51. //这个状态下不会有攻击事件, 所以没必要每一帧检查是否弹药耗尽
  52. var playerPos = Master.LookTarget.GetCenterPosition();
  53. //更新玩家位置
  54. if (_navigationUpdateTimer <= 0)
  55. {
  56. //每隔一段时间秒更改目标位置
  57. _navigationUpdateTimer = _navigationInterval;
  58. Master.NavigationAgent2D.TargetPosition = playerPos;
  59. }
  60. else
  61. {
  62. _navigationUpdateTimer -= delta;
  63. }
  64. if (!Master.NavigationAgent2D.IsNavigationFinished())
  65. {
  66. //移动
  67. Master.DoMove();
  68. }
  69. else
  70. {
  71. //站立
  72. Master.DoIdle();
  73. }
  74. //检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态
  75. if (Master.IsInTailAfterViewRange(playerPos))
  76. {
  77. if (!Master.TestViewRayCast(playerPos)) //看到玩家
  78. {
  79. //关闭射线检测
  80. Master.TestViewRayCastOver();
  81. //切换成发现目标状态
  82. ChangeState(AIStateEnum.AiFollowUp);
  83. return;
  84. }
  85. else
  86. {
  87. //关闭射线检测
  88. Master.TestViewRayCastOver();
  89. }
  90. }
  91. //检测玩家是否在穿墙视野范围内, 直接检测距离即可
  92. _isInViewRange = Master.IsInViewRange(playerPos);
  93. if (_isInViewRange)
  94. {
  95. _viewTimer = 0;
  96. }
  97. else //超出视野
  98. {
  99. if (_viewTimer > 10) //10秒
  100. {
  101. ChangeState(AIStateEnum.AiNormal);
  102. }
  103. else
  104. {
  105. _viewTimer += delta;
  106. }
  107. }
  108. }
  109.  
  110. public override void DebugDraw()
  111. {
  112. var playerPos = Master.LookTarget.GetCenterPosition();
  113. if (_isInViewRange)
  114. {
  115. Master.DrawLine(new Vector2(0, -8), Master.ToLocal(playerPos), Colors.Orange);
  116. }
  117. else
  118. {
  119. Master.DrawLine(new Vector2(0, -8), Master.ToLocal(playerPos), Colors.Blue);
  120. }
  121. }
  122. }