using System.Collections; using System.Collections.Generic; using UnityEngine; /// /// Checks for trigger colliders with IXRHoverable components added, and lets user click or grab them if they /// have IXRClickable or IXRGrabbable scripts on them. /// [RequireComponent(typeof(Collider))] public class ZEDXRGrabber : MonoBehaviour { public ZEDControllerTracker_DemoInputs zedController; private IXRHoverable hoveringObject; private IXRGrabbable grabbingObject; private bool isGrabbing { get { return grabbingObject != null; } } private List collidingHoverables = new List(); private List collidingClickables = new List(); private List collidingGrabbables = new List(); [Space(5)] [Header("Sounds")] public AudioClip clickSound; public AudioClip grabStartSound; public AudioClip grabEndSound; public AudioClip hoverStartSound; // Use this for initialization void Start() { if (!zedController) zedController = GetComponentInParent(); } // Update is called once per frame void Update() { CheckListElementsForValidity(); CheckHovers(); } private void OnTriggerEnter(Collider collision) { IXRHoverable newhoverable = collision.gameObject.GetComponent(); if (newhoverable != null && !collidingHoverables.Contains(newhoverable)) collidingHoverables.Add(newhoverable); IXRClickable newclickable = collision.gameObject.GetComponent(); if (newclickable != null && !collidingClickables.Contains(newclickable)) collidingClickables.Add(newclickable); IXRGrabbable newgrabbable = collision.gameObject.GetComponent(); if (newgrabbable != null && !collidingGrabbables.Contains(newgrabbable)) collidingGrabbables.Add(newgrabbable); } private void OnTriggerExit(Collider collision) { IXRHoverable newhoverable = collision.gameObject.GetComponent(); if (newhoverable != null && collidingHoverables.Contains(newhoverable)) collidingHoverables.Remove(newhoverable); IXRClickable newclickable = collision.gameObject.GetComponent(); if (newclickable != null && collidingClickables.Contains(newclickable)) collidingClickables.Remove(newclickable); IXRGrabbable newgrabbable = collision.gameObject.GetComponent(); if (newgrabbable != null && collidingGrabbables.Contains(newgrabbable)) collidingGrabbables.Remove(newgrabbable); } private void CheckHovers() { //If we're grabbing something, we shouldn't be hovering over anything. if(grabbingObject != null) { if(hoveringObject != null) { if(!Equals(hoveringObject, null)) hoveringObject.OnHoverEnd(); hoveringObject = null; } return; } float nearestdist = Mathf.Infinity; IXRHoverable newhover = null; foreach(IXRHoverable hover in collidingHoverables) { float dist = Vector3.Distance(transform.position, hover.GetTransform().position); if (dist < nearestdist) newhover = hover; } if(hoveringObject != newhover) { if (hoveringObject != null && !hoveringObject.Equals(null)) { hoveringObject.OnHoverEnd(); } if(newhover != null) { PlaySoundIfValid(hoverStartSound); newhover.OnHoverStart(); } hoveringObject = newhover; } } /// /// Checks the interface lists to make sure that they all still exist. Otherwise, if something is destroyed /// or disabled while still in range, we'll still try to interact with it. /// private void CheckListElementsForValidity() { List toremove = new List(); foreach(IXRHoverable hoverable in collidingHoverables) { if(hoverable.Equals(null)) { toremove.Add(hoverable); continue; } Collider col = hoverable.GetTransform().GetComponent(); if(col == null || col.enabled == false) { toremove.Add(hoverable); } } foreach (IXRHoverable deadhoverable in toremove) { collidingHoverables.Remove(deadhoverable); } } public void TryClick() { if (hoveringObject == null) return; IXRClickable newclick = hoveringObject.GetTransform().GetComponent(); if (newclick == null) return; PlaySoundIfValid(clickSound); newclick.OnClick(this); } public void TryGrab() { if (grabbingObject != null) { Debug.Log("Somehow grabbed something while already grabbing something else. Calling ReleaseGrab on that object."); ReleaseGrab(); } if (hoveringObject == null) return; IXRGrabbable newgrab = hoveringObject.GetTransform().GetComponent(); if (newgrab == null) return; if (!Equals(hoveringObject, null)) hoveringObject.OnHoverEnd(); hoveringObject = null; newgrab.OnGrabStart(transform); grabbingObject = newgrab; PlaySoundIfValid(grabStartSound); } public void ReleaseGrab() { if (grabbingObject == null) return; grabbingObject.OnGrabEnd(); grabbingObject = null; PlaySoundIfValid(grabEndSound); } /// /// Plays the given clip, but in a temporary gameobject that appears where the ball is. /// This lets the sound finish playing even if this object is disabled, such as if you press /// the switch hands button. /// private void PlaySoundIfValid(AudioClip clip) { if (clip == null) return; //audioSource.PlayOneShot(clip); GameObject soundgo = new GameObject("Temp Audio Object: " + clip.name); soundgo.transform.position = transform.position; TempAudioObject sound = soundgo.AddComponent(); sound.Setup(clip); } private void OnDisable() { if(hoveringObject != null) { if (!Equals(hoveringObject, null)) hoveringObject.OnHoverEnd(); hoveringObject = null; } if(grabbingObject != null) { grabbingObject.OnGrabEnd(); grabbingObject = null; } collidingHoverables.Clear(); collidingGrabbables.Clear(); collidingClickables.Clear(); } } public interface IXRHoverable { Transform GetTransform(); void OnHoverStart(); void OnHoverEnd(); } public interface IXRClickable { Transform GetTransform(); void OnClick(ZEDXRGrabber clicker); } public interface IXRGrabbable { Transform GetTransform(); void OnGrabStart(Transform grabtransform); void OnGrabEnd(); }