using UnityEngine; using UnityEngine.InputSystem; public class InteractionController : MonoBehaviour { [Header("Interaction Settings")] [Tooltip("How large the proximity bubble is around the player (e.g. 3 meters).")] public float interactionDistance = 3f; [Tooltip("Layers that contain interactable objects (e.g. NPC, Default)")] public LayerMask interactableLayers; [Header("References")] public PlayerUIManager uiManager; [Header("Input")] [Tooltip("The key used to interact")] public Key interactKey = Key.E; // We store whatever we are currently closest to private IInteractable _currentInteractable; private void Update() { if (uiManager == null) return; // Create a sphere around the player to find all interactables in range // Use QueryTriggerInteraction.Ignore so we don't accidentally interact with giant invisible AI/Aggro triggers! Collider[] hits = Physics.OverlapSphere(transform.position, interactionDistance, interactableLayers, QueryTriggerInteraction.Ignore); IInteractable closestInteractable = null; float closestDistance = float.MaxValue; // Loop through everything in our bubble to find the closest one foreach (var hit in hits) { // Ignore our own body if (hit.transform.root == transform.root) continue; IInteractable interactable = hit.GetComponentInParent(); if (interactable != null && interactable.CanInteract()) { float dist = Vector3.Distance(transform.position, hit.ClosestPoint(transform.position)); if (dist < closestDistance) { closestDistance = dist; closestInteractable = interactable; } } } // If we found something valid nearby if (closestInteractable != null) { if (_currentInteractable != closestInteractable) { _currentInteractable = closestInteractable; ShowPrompt(closestInteractable.GetInteractText(), closestInteractable.GetSecondaryInteractText()); } // Listen for input if (Keyboard.current != null && Keyboard.current[interactKey].wasPressedThisFrame) { closestInteractable.Interact(gameObject); } } else { // Nothing in range, or closest thing can't be interacted with anymore if (_currentInteractable != null) { _currentInteractable = null; HidePrompt(); } } } private void ShowPrompt(string actionText, string secondaryText) { if (uiManager.interactionPanel != null) uiManager.interactionPanel.SetActive(true); if (uiManager.interactionText != null) uiManager.interactionText.text = actionText; if (uiManager.interactionSecondaryText != null) { uiManager.interactionSecondaryText.text = secondaryText; } } private void HidePrompt() { if (uiManager.interactionPanel != null) uiManager.interactionPanel.SetActive(false); } // Draws a helpful visual bubble in the Scene view so you can see your interaction range! private void OnDrawGizmosSelected() { Gizmos.color = new Color(0f, 1f, 0f, 0.3f); Gizmos.DrawSphere(transform.position, interactionDistance); } }