using System.Collections; using System.Collections.Generic; using UnityEngine; namespace BNG { public class GrabPointTrigger : MonoBehaviour { public enum HandMovement { Instant, Lerp, None } [Header("Hand Movement")] [Tooltip("How to move the hand to the nearest grab point. If set to 'None', the hand model will remain at the controller.")] public HandMovement MoveInStyle = HandMovement.Instant; [Tooltip("How to move the hand back to the grabber")] public HandMovement MoveOutStyle = HandMovement.Instant; [Tooltip("How to fast to move the hand if MovementStyle = 'Lerp' or 'Linear'")] public float HandSpeed = 20f; [Tooltip("If true the hand model will continue to move towards the closest grab point. If false, the hand will only move towards the closest grab point once upon entering the trigger.")] public bool LiveUpdateNearestGrabPoint = true; [Header("Grabbable Options")] [Tooltip("If specified this Grabbable will be grabbed if the user holds down the grab button while this preview is active")] public Grabbable GrabObject; [Tooltip("If specified this Grabbable must be held for this component to work")] public Grabbable OtherGrabbableMustBeHeld; [Tooltip("Grab Points to move towards when the grabber is within the Trigger area.")] public List GrabPoints; Grabber currentGrabber; Grabbable dummyGrabbable; GrabPoint closestPoint; Grabber grabberInTrigger; void Start() { if(dummyGrabbable == null) { var go = new GameObject("Dummy Grabbable"); dummyGrabbable = go.AddComponent(); dummyGrabbable.transform.parent = transform; dummyGrabbable.transform.localPosition = Vector3.zero; dummyGrabbable.transform.localRotation = Quaternion.identity; // Copy over grab points List grabs = new List(); for (int x = 0; x < GrabPoints.Count; x++) { GrabPoint g = GrabPoints[x]; grabs.Add(g.transform); } dummyGrabbable.GrabPoints = grabs; dummyGrabbable.GrabMechanic = GrabType.Snap; dummyGrabbable.ParentHandModel = false; dummyGrabbable.CanBeDropped = false; // Copy settings over from reference object if available if(GrabObject != null) { dummyGrabbable.GrabButton = GrabObject.GrabButton; dummyGrabbable.Grabtype = GrabObject.Grabtype; } } } void Update() { // holding this object if(dummyGrabbable != null && currentGrabber != null) { // Do we need to drop this object? if(OtherGrabbableMustBeHeld != null && !OtherGrabbableMustBeHeld.BeingHeld) { ReleaseGrabber(); return; } // Is there a new grab point that's closer? if(LiveUpdateNearestGrabPoint) { // dummyGrabbable.transform.position = Transform closestGrab = dummyGrabbable.GetClosestGrabPoint(currentGrabber); if (closestGrab != null) { var newPoint = closestGrab.GetComponent(); if(newPoint != null && newPoint != closestPoint) { UpdateGrabPoint(newPoint); } } } // Move the hand if (MoveInStyle == HandMovement.Lerp) { currentGrabber.HandsGraphics.localPosition = Vector3.Lerp(currentGrabber.HandsGraphics.localPosition, currentGrabber.handsGraphicsGrabberOffset, Time.deltaTime * HandSpeed); currentGrabber.HandsGraphics.localRotation = Quaternion.Slerp(currentGrabber.HandsGraphics.localRotation, Quaternion.identity, Time.deltaTime * HandSpeed); } // User pressed grab key while holding object if (currentGrabber.GetInputDownForGrabbable(dummyGrabbable)) { if(GrabObject != null) { var prevGrabber = currentGrabber; ReleaseGrabber(); prevGrabber.GrabGrabbable(GrabObject); } } } // Are we back in the trigger? if(grabberInTrigger != null && !grabberInTrigger.HoldingItem && currentGrabber == null) { setGrabber(grabberInTrigger); } } public virtual void UpdateGrabPoint(GrabPoint newPoint) { closestPoint = newPoint; // Update hand animation // dummyGrabbable.CustomHandPose = newPoint.HandPose; dummyGrabbable.handPoseType = newPoint.handPoseType; dummyGrabbable.SelectedHandPose = newPoint.SelectedHandPose; // Move Hand Graphics if they are available if (currentGrabber != null && currentGrabber.HandsGraphics != null) { if (MoveInStyle != HandMovement.None) { currentGrabber.HandsGraphics.parent = closestPoint.transform; } // Move hands in place if (MoveInStyle == HandMovement.Instant) { currentGrabber.HandsGraphics.localPosition = currentGrabber.handsGraphicsGrabberOffset; currentGrabber.HandsGraphics.localEulerAngles = Vector3.zero; } } } void OnTriggerEnter(Collider other) { // Object isn't being held, ignore this if(OtherGrabbableMustBeHeld != null && !OtherGrabbableMustBeHeld.BeingHeld) { return; } // Already have something in the trigger if(grabberInTrigger != null) { return; } // Our component has been disabled if(!this.isActiveAndEnabled || dummyGrabbable == null) { return; } Grabber grab = other.GetComponent(); if (grab != null && !grab.HoldingItem && currentGrabber == null) { // Check if any Grab Points have been found Transform closestGrab = dummyGrabbable.GetClosestGrabPoint(grab); if(closestGrab != null) { closestPoint = closestGrab.GetComponent(); } else { closestPoint = null; } grabberInTrigger = grab; // Update Grabber if (closestPoint != null) { dummyGrabbable.ActiveGrabPoint = closestPoint; setGrabber(grab); } } } void OnTriggerExit(Collider other) { Grabber grab = other.GetComponent(); // No longer inside trigger if (grab != null && grab == grabberInTrigger) { grabberInTrigger = null; } // Release grabber if out if (grab != null && grab == currentGrabber) { ReleaseGrabber(); } } void setGrabber(Grabber theGrabber) { currentGrabber = theGrabber; dummyGrabbable.CanBeDropped = false; dummyGrabbable.BeingHeld = true; currentGrabber.HeldGrabbable = dummyGrabbable; UpdateGrabPoint(closestPoint); } public virtual void ReleaseGrabber() { if (currentGrabber != null) { dummyGrabbable.CanBeDropped = true; dummyGrabbable.BeingHeld = false; currentGrabber.HeldGrabbable = null; if (MoveOutStyle == HandMovement.Instant) { currentGrabber.ResetHandGraphics(); } else if (MoveOutStyle == HandMovement.Lerp) { currentGrabber.ResetHandGraphics(); } currentGrabber = null; } } } }