101 lines
3.5 KiB
C#
101 lines
3.5 KiB
C#
|
|
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<IInteractable>();
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
}
|