using System.Collections;
using UnityEngine;

public class Grabbable : MonoBehaviour, IGrabbable
{
    public enum GrabType
    {
        Cylindrical,
        Box,
        Pinch,
        Handle
    }

    private Rigidbody rb;
    public float heaviness;
    private string defaultlayer;
    private Vector3 originalScale;
    private Quaternion objectRotation;
    public GrabType grabType;

    bool isHeld;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        defaultlayer = LayerMask.LayerToName(gameObject.layer);
    }

    void Update()
    {
    }

    public void OnGrab(Transform anchor)
    {
        StopAllCoroutines();
        transform.SetParent(anchor);
        switch (grabType)
        {
            case GrabType.Handle:
                transform.rotation = anchor.rotation;
                objectRotation = anchor.rotation;
                break;
        }

        SetLayer(gameObject, LayerMask.LayerToName(anchor.gameObject.layer));
        rb.isKinematic = true;
        StartCoroutine(Glide(anchor));
    }

    public void OnRelease(Vector3 dropPoint)
    {
        StopAllCoroutines();
        StartCoroutine(Release(dropPoint));
        transform.SetParent(null);
        transform.rotation = objectRotation;
        SetLayer(gameObject, defaultlayer);
    }

    public IEnumerator Glide(Transform anchor)
    {
        while (Vector3.Distance(transform.position, anchor.position) > 0.05f)
        {
            transform.position = Vector3.Lerp(transform.position, anchor.position, heaviness * Time.deltaTime);
            yield return null;
        }
    }

    public IEnumerator Release(Vector3 anchor)
    {
        while (Vector3.Distance(transform.position, anchor) > 0.05f)
        {
            transform.position = Vector3.Lerp(transform.position, anchor, heaviness * Time.deltaTime);
            yield return null;
        }

        rb.isKinematic = false;
    }

    public void SetLayer(GameObject rootObject, string layerName)
    {
        int newLayer = LayerMask.NameToLayer(layerName);

        Transform[] objectEntire = rootObject.GetComponentsInChildren<Transform>(true);

        foreach (Transform child in objectEntire)
        {
            child.gameObject.layer = newLayer;
        }
    }
}

using UnityEngine;
using UnityEngine.InputSystem;

public class HandController : MonoBehaviour
{
    [SerializeField] private Transform rayPos;
    [SerializeField] private float range;

    public enum HandType { Left, Right };
    private InputSystem_Actions inputSystem;
    private InputAction pickUpAction;

    [SerializeField] private Animator animator;

    public Transform handAnchor;
    public Transform handleAnchor;
    [Header("Hand Setup")]
    public HandType handtype;
    public GameObject objectInHand;

    private Grabbable.GrabType objectType;

    void Awake()
    {
        inputSystem = new InputSystem_Actions();
    }

    private void OnEnable()
    {
        if (handtype == HandType.Left)
        {
            pickUpAction = inputSystem.Player.LeftHand;
        }
        else
        {
            pickUpAction = inputSystem.Player.RightHand;
        }
        if (pickUpAction != null)
        {
            pickUpAction.started += TryPickUp;
        }
        inputSystem.Enable();
    }

    private void OnDisable()
    {
        if (pickUpAction != null)
        {
            pickUpAction.started -= TryPickUp;
        }
        inputSystem.Disable();
    }

    void Update()
    {
    }

    private void TryPickUp(InputAction.CallbackContext context)
    {
        Ray ray = new Ray(rayPos.position, rayPos.forward);
        RaycastHit hit;

        if (objectInHand != null)
        {
            if (Physics.Raycast(ray, out hit, range))
            {
                SetAnim(objectInHand.GetComponent<Grabbable>().grabType, false);
                animator.SetTrigger("Grab");
                if (hit.collider.TryGetComponent(out IInteractable interact))
                {
                    interact.OnInteract(this);
                }
                else
                {
                    objectInHand.GetComponent<IGrabbable>().OnRelease(hit.point);
                    objectInHand = null;
                }
            }
        }
        else
        {
            if (Physics.Raycast(ray, out hit, range))
            {
                if (hit.collider.TryGetComponent(out IGrabbable grab))
                {
                    grab.OnGrab(handAnchor);
                    objectInHand = hit.collider.gameObject;
                    Grabbable grabbable = hit.collider.GetComponent<Grabbable>();
                    SetAnim(objectInHand.GetComponent<Grabbable>().grabType, true);
                }
                else if (hit.collider.TryGetComponent(out IInteractable interact))
                {
                    interact.OnInteract(this);
                }
                animator.SetTrigger("Grab");
            }
        }
    }

    private void SetAnim(Grabbable.GrabType item, bool isActive)
    {
        objectType = item;
        switch (item)
        {
            case Grabbable.GrabType.Handle:
                animator.SetBool("IsHoldingMug", isActive);
                break;
        }
    }
}

注意:本翻译结果仅供参考,可能存在少许错误或不准确之处。