namespace Tilia.Interactions.Interactables.Interactables { using System; using System.Collections; using Tilia.Interactions.Interactables.Interactors; using UnityEngine; using UnityEngine.Events; using Zinnia.Extension; /// /// Attempts to grab the given Interactable to the given Interactor. /// public class InteractableGrabber : MonoBehaviour { /// /// Defines the event with the . /// [Serializable] public class UnityEvent : UnityEvent { } [Tooltip("The Interactor to grab to.")] [SerializeField] private InteractorFacade interactor; /// /// The Interactor to grab to. /// public InteractorFacade Interactor { get { return interactor; } set { interactor = value; } } [Tooltip("The Interactable to grab.")] [SerializeField] private InteractableFacade interactable; /// /// The Interactable to grab. /// public InteractableFacade Interactable { get { return interactable; } set { interactable = value; } } /// /// Emitted when the Grab has occurred. /// public UnityEvent Grabbed = new UnityEvent(); /// /// A reusable instance of . /// protected static readonly WaitForEndOfFrame DelayInstruction = new WaitForEndOfFrame(); /// /// The routine for managing the grab. /// protected Coroutine grabRoutine; /// /// Clears . /// public virtual void ClearInteractor() { if (!this.IsValidState()) { return; } Interactor = default; } /// /// Clears . /// public virtual void ClearInteractable() { if (!this.IsValidState()) { return; } Interactable = default; } /// /// Sets the from the given . /// /// The object to search for the Interactor on. public virtual void SetInteractorFromGameObject(GameObject interactor) { Interactor = interactor.TryGetComponent(true, true); } /// /// Sets the from the given . /// /// The object to search for the Interactable on. public virtual void SetInteractableFromGameObject(GameObject interactable) { Interactable = interactable.TryGetComponent(true, true); } /// /// Attempts to grab the to the . /// public virtual void DoGrab() { if (!this.IsValidState() || Interactor == null || Interactable == null) { return; } if (Interactable.IsGrabbed) { Interactable.Ungrab(); } CancelGrabRoutine(); grabRoutine = StartCoroutine(GrabAtEndOfFrame()); } protected virtual void OnDisable() { CancelGrabRoutine(); } /// /// Performs the grab at the end of the current frame. /// /// Coroutine enumerator. protected virtual IEnumerator GrabAtEndOfFrame() { yield return DelayInstruction; if (Interactor.GrabConfiguration.GrabAction.Value) { bool cachedSetting = Interactor.GrabConfiguration.TouchBeforeForceGrab; Interactor.GrabConfiguration.TouchBeforeForceGrab = false; Interactor.Grab(Interactable); Interactor.GrabConfiguration.TouchBeforeForceGrab = cachedSetting; Grabbed?.Invoke(Interactable); } } /// /// Cancels the existing running grab coroutine. /// protected virtual void CancelGrabRoutine() { if (grabRoutine == null) { return; } StopCoroutine(grabRoutine); grabRoutine = null; } } }