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.

140 lines
5.2 KiB

5 years ago
  1. using System.Linq;
  2. using Unity.FPS.Game;
  3. using UnityEngine;
  4. using UnityEngine.Events;
  5. namespace Unity.FPS.AI
  6. {
  7. public class DetectionModule : MonoBehaviour
  8. {
  9. [Tooltip("The point representing the source of target-detection raycasts for the enemy AI")]
  10. public Transform DetectionSourcePoint;
  11. [Tooltip("The max distance at which the enemy can see targets")]
  12. public float DetectionRange = 20f;
  13. [Tooltip("The max distance at which the enemy can attack its target")]
  14. public float AttackRange = 10f;
  15. [Tooltip("Time before an enemy abandons a known target that it can't see anymore")]
  16. public float KnownTargetTimeout = 4f;
  17. [Tooltip("Optional animator for OnShoot animations")]
  18. public Animator Animator;
  19. public UnityAction onDetectedTarget;
  20. public UnityAction onLostTarget;
  21. public GameObject KnownDetectedTarget { get; private set; }
  22. public bool IsTargetInAttackRange { get; private set; }
  23. public bool IsSeeingTarget { get; private set; }
  24. public bool HadKnownTarget { get; private set; }
  25. protected float TimeLastSeenTarget = Mathf.NegativeInfinity;
  26. ActorsManager m_ActorsManager;
  27. const string k_AnimAttackParameter = "Attack";
  28. const string k_AnimOnDamagedParameter = "OnDamaged";
  29. protected virtual void Start()
  30. {
  31. m_ActorsManager = FindObjectOfType<ActorsManager>();
  32. DebugUtility.HandleErrorIfNullFindObject<ActorsManager, DetectionModule>(m_ActorsManager, this);
  33. }
  34. public virtual void HandleTargetDetection(Actor actor, Collider[] selfColliders)
  35. {
  36. // Handle known target detection timeout
  37. if (KnownDetectedTarget && !IsSeeingTarget && (Time.time - TimeLastSeenTarget) > KnownTargetTimeout)
  38. {
  39. KnownDetectedTarget = null;
  40. }
  41. // Find the closest visible hostile actor
  42. float sqrDetectionRange = DetectionRange * DetectionRange;
  43. IsSeeingTarget = false;
  44. float closestSqrDistance = Mathf.Infinity;
  45. foreach (Actor otherActor in m_ActorsManager.Actors)
  46. {
  47. if (otherActor.Affiliation != actor.Affiliation)
  48. {
  49. float sqrDistance = (otherActor.transform.position - DetectionSourcePoint.position).sqrMagnitude;
  50. if (sqrDistance < sqrDetectionRange && sqrDistance < closestSqrDistance)
  51. {
  52. // Check for obstructions
  53. RaycastHit[] hits = Physics.RaycastAll(DetectionSourcePoint.position,
  54. (otherActor.AimPoint.position - DetectionSourcePoint.position).normalized, DetectionRange,
  55. -1, QueryTriggerInteraction.Ignore);
  56. RaycastHit closestValidHit = new RaycastHit();
  57. closestValidHit.distance = Mathf.Infinity;
  58. bool foundValidHit = false;
  59. foreach (var hit in hits)
  60. {
  61. if (!selfColliders.Contains(hit.collider) && hit.distance < closestValidHit.distance)
  62. {
  63. closestValidHit = hit;
  64. foundValidHit = true;
  65. }
  66. }
  67. if (foundValidHit)
  68. {
  69. Actor hitActor = closestValidHit.collider.GetComponentInParent<Actor>();
  70. if (hitActor == otherActor)
  71. {
  72. IsSeeingTarget = true;
  73. closestSqrDistance = sqrDistance;
  74. TimeLastSeenTarget = Time.time;
  75. KnownDetectedTarget = otherActor.AimPoint.gameObject;
  76. }
  77. }
  78. }
  79. }
  80. }
  81. IsTargetInAttackRange = KnownDetectedTarget != null &&
  82. Vector3.Distance(transform.position, KnownDetectedTarget.transform.position) <=
  83. AttackRange;
  84. // Detection events
  85. if (!HadKnownTarget &&
  86. KnownDetectedTarget != null)
  87. {
  88. OnDetect();
  89. }
  90. if (HadKnownTarget &&
  91. KnownDetectedTarget == null)
  92. {
  93. OnLostTarget();
  94. }
  95. // Remember if we already knew a target (for next frame)
  96. HadKnownTarget = KnownDetectedTarget != null;
  97. }
  98. public virtual void OnLostTarget() => onLostTarget?.Invoke();
  99. public virtual void OnDetect() => onDetectedTarget?.Invoke();
  100. public virtual void OnDamaged(GameObject damageSource)
  101. {
  102. TimeLastSeenTarget = Time.time;
  103. KnownDetectedTarget = damageSource;
  104. if (Animator)
  105. {
  106. Animator.SetTrigger(k_AnimOnDamagedParameter);
  107. }
  108. }
  109. public virtual void OnAttack()
  110. {
  111. if (Animator)
  112. {
  113. Animator.SetTrigger(k_AnimAttackParameter);
  114. }
  115. }
  116. }
  117. }