2021년 4학년 1학기 기업연계프로젝트2 컴퓨터소프트웨어공학과 <원광투어팀> 팀장 : 송유진 팀원 : 김나영, 이경희, 한유진
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

169 lines
5.5 KiB

5 years ago
  1. using Unity.FPS.Game;
  2. using UnityEngine;
  3. namespace Unity.FPS.AI
  4. {
  5. [RequireComponent(typeof(EnemyController))]
  6. public class EnemyTurret : MonoBehaviour
  7. {
  8. public enum AIState
  9. {
  10. Idle,
  11. Attack,
  12. }
  13. public Transform TurretPivot;
  14. public Transform TurretAimPoint;
  15. public Animator Animator;
  16. public float AimRotationSharpness = 5f;
  17. public float LookAtRotationSharpness = 2.5f;
  18. public float DetectionFireDelay = 1f;
  19. public float AimingTransitionBlendTime = 1f;
  20. [Tooltip("The random hit damage effects")]
  21. public ParticleSystem[] RandomHitSparks;
  22. public ParticleSystem[] OnDetectVfx;
  23. public AudioClip OnDetectSfx;
  24. public AIState AiState { get; private set; }
  25. EnemyController m_EnemyController;
  26. Health m_Health;
  27. Quaternion m_RotationWeaponForwardToPivot;
  28. float m_TimeStartedDetection;
  29. float m_TimeLostDetection;
  30. Quaternion m_PreviousPivotAimingRotation;
  31. Quaternion m_PivotAimingRotation;
  32. const string k_AnimOnDamagedParameter = "OnDamaged";
  33. const string k_AnimIsActiveParameter = "IsActive";
  34. void Start()
  35. {
  36. m_Health = GetComponent<Health>();
  37. DebugUtility.HandleErrorIfNullGetComponent<Health, EnemyTurret>(m_Health, this, gameObject);
  38. m_Health.OnDamaged += OnDamaged;
  39. m_EnemyController = GetComponent<EnemyController>();
  40. DebugUtility.HandleErrorIfNullGetComponent<EnemyController, EnemyTurret>(m_EnemyController, this,
  41. gameObject);
  42. m_EnemyController.onDetectedTarget += OnDetectedTarget;
  43. m_EnemyController.onLostTarget += OnLostTarget;
  44. // Remember the rotation offset between the pivot's forward and the weapon's forward
  45. m_RotationWeaponForwardToPivot =
  46. Quaternion.Inverse(m_EnemyController.GetCurrentWeapon().WeaponMuzzle.rotation) * TurretPivot.rotation;
  47. // Start with idle
  48. AiState = AIState.Idle;
  49. m_TimeStartedDetection = Mathf.NegativeInfinity;
  50. m_PreviousPivotAimingRotation = TurretPivot.rotation;
  51. }
  52. void Update()
  53. {
  54. UpdateCurrentAiState();
  55. }
  56. void LateUpdate()
  57. {
  58. UpdateTurretAiming();
  59. }
  60. void UpdateCurrentAiState()
  61. {
  62. // Handle logic
  63. switch (AiState)
  64. {
  65. case AIState.Attack:
  66. bool mustShoot = Time.time > m_TimeStartedDetection + DetectionFireDelay;
  67. // Calculate the desired rotation of our turret (aim at target)
  68. Vector3 directionToTarget =
  69. (m_EnemyController.KnownDetectedTarget.transform.position - TurretAimPoint.position).normalized;
  70. Quaternion offsettedTargetRotation =
  71. Quaternion.LookRotation(directionToTarget) * m_RotationWeaponForwardToPivot;
  72. m_PivotAimingRotation = Quaternion.Slerp(m_PreviousPivotAimingRotation, offsettedTargetRotation,
  73. (mustShoot ? AimRotationSharpness : LookAtRotationSharpness) * Time.deltaTime);
  74. // shoot
  75. if (mustShoot)
  76. {
  77. Vector3 correctedDirectionToTarget =
  78. (m_PivotAimingRotation * Quaternion.Inverse(m_RotationWeaponForwardToPivot)) *
  79. Vector3.forward;
  80. m_EnemyController.TryAtack(TurretAimPoint.position + correctedDirectionToTarget);
  81. }
  82. break;
  83. }
  84. }
  85. void UpdateTurretAiming()
  86. {
  87. switch (AiState)
  88. {
  89. case AIState.Attack:
  90. TurretPivot.rotation = m_PivotAimingRotation;
  91. break;
  92. default:
  93. // Use the turret rotation of the animation
  94. TurretPivot.rotation = Quaternion.Slerp(m_PivotAimingRotation, TurretPivot.rotation,
  95. (Time.time - m_TimeLostDetection) / AimingTransitionBlendTime);
  96. break;
  97. }
  98. m_PreviousPivotAimingRotation = TurretPivot.rotation;
  99. }
  100. void OnDamaged(float dmg, GameObject source)
  101. {
  102. if (RandomHitSparks.Length > 0)
  103. {
  104. int n = Random.Range(0, RandomHitSparks.Length - 1);
  105. RandomHitSparks[n].Play();
  106. }
  107. Animator.SetTrigger(k_AnimOnDamagedParameter);
  108. }
  109. void OnDetectedTarget()
  110. {
  111. if (AiState == AIState.Idle)
  112. {
  113. AiState = AIState.Attack;
  114. }
  115. for (int i = 0; i < OnDetectVfx.Length; i++)
  116. {
  117. OnDetectVfx[i].Play();
  118. }
  119. if (OnDetectSfx)
  120. {
  121. AudioUtility.CreateSFX(OnDetectSfx, transform.position, AudioUtility.AudioGroups.EnemyDetection, 1f);
  122. }
  123. Animator.SetBool(k_AnimIsActiveParameter, true);
  124. m_TimeStartedDetection = Time.time;
  125. }
  126. void OnLostTarget()
  127. {
  128. if (AiState == AIState.Attack)
  129. {
  130. AiState = AIState.Idle;
  131. }
  132. for (int i = 0; i < OnDetectVfx.Length; i++)
  133. {
  134. OnDetectVfx[i].Stop();
  135. }
  136. Animator.SetBool(k_AnimIsActiveParameter, false);
  137. m_TimeLostDetection = Time.time;
  138. }
  139. }
  140. }