PlayerInteraction.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using UnityEngine;
  2. namespace HQFPSWeapons
  3. {
  4. /// <summary>
  5. /// Sends a ray from the center of the camera, in the game world.
  6. /// Gathers data about what is in front of the player, and stores it in a variable.
  7. /// </summary>
  8. public class PlayerInteraction : PlayerComponent
  9. {
  10. [SerializeField]
  11. private Camera m_WorldCamera = null;
  12. [SerializeField]
  13. [Tooltip("The maximum distance at which you can interact with objects.")]
  14. private float m_InteractionDistance = 2f;
  15. [SerializeField]
  16. [Range(0f, 60f)]
  17. private float m_MaxInteractionAngle = 30f;
  18. [SerializeField]
  19. private LayerMask m_LayerMask = new LayerMask();
  20. private InteractiveObject m_InteractedObject;
  21. private void Awake()
  22. {
  23. Player.WantsToInteract.AddChangeListener(OnChanged_WantsToInteract);
  24. }
  25. private void OnChanged_WantsToInteract(bool wantsToInteract)
  26. {
  27. var raycastData = Player.RaycastData.Get();
  28. var wantedToInteractPreviously = Player.WantsToInteract.GetPreviousValue();
  29. var wantsToInteractNow = wantsToInteract;
  30. if(raycastData != null && raycastData.IsInteractive)
  31. {
  32. if(!wantedToInteractPreviously && wantsToInteractNow)
  33. {
  34. raycastData.InteractiveObject.OnInteractionStart(Player);
  35. m_InteractedObject = raycastData.InteractiveObject;
  36. }
  37. }
  38. if(m_InteractedObject != null && wantedToInteractPreviously && !wantsToInteractNow)
  39. {
  40. m_InteractedObject.OnInteractionEnd(Player);
  41. m_InteractedObject = null;
  42. }
  43. }
  44. private void Update()
  45. {
  46. var ray = m_WorldCamera.ViewportPointToRay(Vector2.one * 0.5f);
  47. var lastRaycastData = Player.RaycastData.Get();
  48. var collidersInRange = Physics.OverlapSphere(m_WorldCamera.transform.position, m_InteractionDistance, m_LayerMask, QueryTriggerInteraction.Collide);
  49. float smallestAngle = 1000f;
  50. InteractiveObject closestObject = null;
  51. int closestObjectIndex = -1;
  52. Vector3 cameraPosition = m_WorldCamera.transform.position;
  53. Vector3 cameraDirection = m_WorldCamera.transform.forward;
  54. for(int i = 0;i < collidersInRange.Length; i ++)
  55. {
  56. InteractiveObject interactiveObject = collidersInRange[i].GetComponent<InteractiveObject>();
  57. RaycastHit hitInfo;
  58. if(interactiveObject != null && Physics.Linecast(cameraPosition, interactiveObject.transform.position + (interactiveObject.transform.position - cameraPosition).normalized * 0.05f, out hitInfo, m_LayerMask))
  59. {
  60. if(hitInfo.collider == null || hitInfo.collider == collidersInRange[i])
  61. {
  62. float angle = Vector3.Angle(cameraDirection, interactiveObject.transform.position - cameraPosition);
  63. if(angle < smallestAngle)
  64. {
  65. smallestAngle = angle;
  66. closestObject = interactiveObject;
  67. closestObjectIndex = i;
  68. }
  69. }
  70. }
  71. }
  72. if(smallestAngle < m_MaxInteractionAngle && ((lastRaycastData != null && lastRaycastData.Collider != collidersInRange[closestObjectIndex]) || lastRaycastData == null))
  73. {
  74. var raycastData = new RaycastData(collidersInRange[closestObjectIndex], closestObject);
  75. Player.RaycastData.Set(raycastData);
  76. bool startedRaycastingOnObject =
  77. lastRaycastData != null &&
  78. raycastData.IsInteractive &&
  79. raycastData.InteractiveObject != lastRaycastData.InteractiveObject;
  80. if(startedRaycastingOnObject)
  81. raycastData.InteractiveObject.OnRaycastStart(Player);
  82. else if(raycastData.IsInteractive)
  83. raycastData.InteractiveObject.OnRaycastUpdate(Player);
  84. else if(lastRaycastData != null && lastRaycastData.InteractiveObject != null)
  85. lastRaycastData.InteractiveObject.OnRaycastEnd(Player);
  86. }
  87. else if(smallestAngle > m_MaxInteractionAngle)
  88. {
  89. Player.RaycastData.Set(null);
  90. // Let the object know the ray it's not on it anymore.
  91. if(lastRaycastData != null && lastRaycastData.IsInteractive)
  92. {
  93. if(lastRaycastData.IsInteractive)
  94. lastRaycastData.InteractiveObject.OnRaycastEnd(Player);
  95. }
  96. }
  97. // if(Physics.Raycast(ray, out hitInfo, m_InteractionDistance, m_LayerMask, QueryTriggerInteraction.Collide) && ((lastRaycastData != null && lastRaycastData.HitInfo.collider != hitInfo.collider) || lastRaycastData == null))
  98. // {
  99. // var raycastData = new RaycastData(hitInfo);
  100. // Player.RaycastData.Set(raycastData);
  101. //
  102. // bool startedRaycastingOnObject =
  103. // lastRaycastData != null &&
  104. // raycastData.IsInteractive &&
  105. // raycastData.InteractiveObject != lastRaycastData.InteractiveObject;
  106. //
  107. // if(startedRaycastingOnObject)
  108. // raycastData.InteractiveObject.OnRaycastStart(Player);
  109. // else if(raycastData.IsInteractive)
  110. // raycastData.InteractiveObject.OnRaycastUpdate(Player);
  111. // else if(lastRaycastData != null && lastRaycastData.InteractiveObject != null)
  112. // lastRaycastData.InteractiveObject.OnRaycastEnd(Player);
  113. // }
  114. // else if(hitInfo.collider == null)
  115. // {
  116. // Player.RaycastData.Set(null);
  117. //
  118. // // Let the object know the ray it's not on it anymore.
  119. // if(lastRaycastData != null && lastRaycastData.IsInteractive)
  120. // {
  121. // if(lastRaycastData.IsInteractive)
  122. // lastRaycastData.InteractiveObject.OnRaycastEnd(Player);
  123. // }
  124. // }
  125. // bool objectInProximity = Physics.CheckSphere(transform.position + transform.TransformVector(m_ProximityDetection.Offset), m_ProximityDetection.Radius, m_ProximityDetection.Mask);
  126. //
  127. // Player.ObjectInProximity.Set(objectInProximity);
  128. if(m_InteractedObject != null)
  129. m_InteractedObject.OnInteractionUpdate(Player);
  130. }
  131. // private void OnDrawGizmosSelected()
  132. // {
  133. // Gizmos.color = Color.red;
  134. // Gizmos.DrawWireSphere(transform.position + transform.TransformVector(m_ProximityDetection.Offset), m_ProximityDetection.Radius);
  135. // }
  136. // // -------------------- Internal --------------------
  137. // [Serializable]
  138. // public struct ProximityDetection
  139. // {
  140. // public Vector3 Offset;
  141. //
  142. // [Range(0f, 2f)]
  143. // public float Radius;
  144. //
  145. // public LayerMask Mask;
  146. // }
  147. }
  148. }