Files
2026-06-22 16:18:34 +02:00

239 lines
8.1 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.InputSystem; // optional, used only if you assign InputActionReference
//Interacting with physics objects and interactive objects
namespace Raygeas
{
public class PlayerInteractions : MonoBehaviour
{
[Header("Interaction variables")]
[Tooltip("Maximum distance from player to object of interaction")]
[SerializeField] private float interactionDistance = 3f;
[Tooltip("The player's main camera")]
[SerializeField] private Camera mainCamera;
[Tooltip("Parent object where the object to be lifted becomes")]
[SerializeField] private Transform pickupParent;
[Header("Input System (optional)")]
[Tooltip("Interact action (Input System). If assigned, used instead of interactionKey)")]
[SerializeField] private InputActionReference interactAction;
[Header("Object Following")]
[Tooltip("Minimum speed of the lifted object")]
[SerializeField] private float minSpeed = 0;
[Tooltip("Maximum speed of the lifted object")]
[SerializeField] private float maxSpeed = 3000f;
[Header("UI")]
[Tooltip("Background object for text")]
[SerializeField] private Image uiPanel;
[Tooltip("Text holder")]
[SerializeField] private Text panelText;
[Tooltip("Text when an object can be lifted")]
[SerializeField] private string itemPickUpText;
[Tooltip("Text when an object can be drop")]
[SerializeField] private string itemDropText;
[Tooltip("Text when an interactive object can be opened")]
[SerializeField] private string interactiveOpenText;
[Tooltip("Text when an interactive object can be closed")]
[SerializeField] private string interactiveCloseText;
//Private variables.
private PhysicsObject _physicsObject;
private PhysicsObject _currentlyPickedUpObject;
private PhysicsObject _lookObject;
private Quaternion _lookRotation;
private Rigidbody _pickupRigidBody;
private Interactive _lookInteractive;
private float _currentSpeed = 0f;
private float _currentDistance = 0f;
private CharacterController _characterController;
private Collider _selection;
private void Start()
{
mainCamera = Camera.main;
_characterController = GetComponent<CharacterController>();
}
private void OnEnable()
{
if (interactAction != null && interactAction.action != null)
{
interactAction.action.Enable();
}
}
private void OnDisable()
{
if (interactAction != null && interactAction.action != null)
{
interactAction.action.Disable();
}
}
private void Update()
{
Interactions();
LegCheck();
}
//Determine which object we are now looking at, depending on the component
private void Interactions()
{
Ray ray = mainCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));
if (_selection == null)
{
_lookInteractive = null;
_lookObject = null;
}
if (Physics.Raycast(ray, out RaycastHit interactionHit, interactionDistance))
{
Collider selection = interactionHit.collider;
if (selection.GetComponent<PhysicsObject>() != null)
{
_lookObject = selection.gameObject.GetComponent<PhysicsObject>();
ShowItemUI();
}
else if (selection.GetComponent<Interactive>() != null)
{
_lookInteractive = selection.gameObject.GetComponent<Interactive>();
ShowInteractiveUI();
// input: use InputActionReference if provided
bool interactPressed = false;
if (interactAction != null && interactAction.action != null)
{
interactPressed = interactAction.action.triggered;
}
if (interactPressed)
{
_lookInteractive.PlayInteractiveAnimation();
}
}
selection = _selection;
}
if (_lookObject == null && _lookInteractive == null)
{
uiPanel.gameObject.SetActive(false);
}
// input: use InputActionReference if provided, otherwise KeyCode
bool interactionDown = false;
if (interactAction != null && interactAction.action != null)
{
interactionDown = interactAction.action.triggered;
}
if (interactionDown)
{
if (_currentlyPickedUpObject == null && _lookObject != null)
{
PickUpObject();
}
else
{
BreakConnection();
}
}
}
//Disconnects from the object when the player attempts to step on the object, prevents flight on the object
private void LegCheck()
{
Vector3 spherePosition = _characterController.center + transform.position;
RaycastHit legCheck;
if (Physics.SphereCast(spherePosition, 0.3f, Vector3.down, out legCheck, 2.0f))
{
if (legCheck.collider.GetComponent<PhysicsObject>())
{
BreakConnection();
}
}
}
//Velocity movement toward pickup parent
[System.Obsolete]
private void FixedUpdate()
{
if (_currentlyPickedUpObject != null)
{
_currentDistance = Vector3.Distance(pickupParent.position, _pickupRigidBody.position);
_currentSpeed = Mathf.SmoothStep(minSpeed, maxSpeed, _currentDistance / interactionDistance);
_currentSpeed *= Time.fixedDeltaTime;
Vector3 direction = pickupParent.position - _pickupRigidBody.position;
_pickupRigidBody.velocity = direction.normalized * _currentSpeed;
}
}
//Picking up an looking object
public void PickUpObject()
{
_physicsObject = _lookObject.GetComponentInChildren<PhysicsObject>();
_currentlyPickedUpObject = _lookObject;
_lookRotation = _currentlyPickedUpObject.transform.rotation;
_pickupRigidBody = _currentlyPickedUpObject.GetComponent<Rigidbody>();
_pickupRigidBody.constraints = RigidbodyConstraints.FreezeRotation;
_pickupRigidBody.transform.rotation = _lookRotation;
_physicsObject.playerInteraction = this;
StartCoroutine(_physicsObject.PickUp());
}
//Release the object
public void BreakConnection()
{
if (_currentlyPickedUpObject)
{
_pickupRigidBody.constraints = RigidbodyConstraints.None;
_physicsObject.pickedUp = false;
_currentlyPickedUpObject = null;
_physicsObject = null;
_lookObject = null;
_currentDistance = 0;
}
}
//Show interface elements when hovering over an object
private void ShowInteractiveUI()
{
uiPanel.gameObject.SetActive(true);
if (_lookInteractive.interactiveObjectOpen)
{
panelText.text = interactiveCloseText;
}
else
{
panelText.text = interactiveOpenText;
}
}
private void ShowItemUI()
{
uiPanel.gameObject.SetActive(true);
if (_currentlyPickedUpObject == null)
{
panelText.text = itemPickUpText;
}
else if (_currentlyPickedUpObject != null)
{
panelText.text = itemDropText;
}
}
}
}