using System.Collections; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.UI.HandCoach { /// /// This class provides functionality to move the hand hint from a tracking position to a target position over time. /// public class MoveToTarget : MonoBehaviour { [Tooltip("Object to track.")] [SerializeField] private GameObject trackingObject = null; /// /// Object to track. /// public GameObject TrackingObject { get { return trackingObject; } set { trackingObject = value; } } [Tooltip("Target to move to.")] [SerializeField] private GameObject targetObject = null; /// /// Target to move to. /// public GameObject TargetObject { get { return targetObject; } set { targetObject = value; } } [Tooltip("Shared parent between tracking and target objects used for relative local positions.")] [SerializeField] private GameObject rootObject = null; /// /// Shared parent between tracking and target objects used for relative local positions. /// public GameObject RootObject { get { return rootObject; } set { rootObject = value; } } [Tooltip("Duration of move from tracking object to target object in seconds.")] [SerializeField] private float duration = 1.38f; /// /// Duration of move from tracking object to target object in seconds. /// public float Duration { get { return duration; } set { duration = value; } } [Tooltip("Tunable offset to get the GameObject to arrive at the right target position.")] [SerializeField] private Vector3 targetOffset = new Vector3(0f, 0f, 0f); /// /// Tunable offset to get the GameObject to arrive at the right target position. /// public Vector3 TargetOffset { get { return targetOffset; } set { targetOffset = value; } } [Tooltip("Lerp curve that controls the animation position over time from the trackingObject to the targetObject.")] [SerializeField] private AnimationCurve animationCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f); /// /// Lerp curve that controls the animation position over time from the trackingObject to the targetObject. /// public AnimationCurve AnimationCurve { get { return animationCurve; } set { animationCurve = value; } } // The local position of this gameObject relative to the root object private Vector3 relativePositionTrackingToRoot; // The local position of targetObject relative to the root object private Vector3 relativeTargetPositionToRoot; // bool to determine when to stop the follow sequence private bool followingTargetObject; // Since this script can attach to an object with an animator, we need to update position in LateUpdate private void LateUpdate() { if (TargetObject != null && RootObject != null) { relativeTargetPositionToRoot = GetRelativeLocalPosition(TargetObject, RootObject) + TargetOffset; transform.parent.localPosition = relativePositionTrackingToRoot; } } /// /// Starts coroutine to lerp from current position to target position /// public void MoveToTargetPosition() { if (relativeTargetPositionToRoot != Vector3.zero) { followingTargetObject = false; StartCoroutine(MoveHintSequence()); } } private IEnumerator MoveHintSequence() { Vector3 origin = relativePositionTrackingToRoot; float t = 0; while (t <= Duration) { relativePositionTrackingToRoot = Vector3.Lerp(origin, relativeTargetPositionToRoot, AnimationCurve.Evaluate(t / Duration)); t += Time.deltaTime; yield return null; } } /// /// Starts coroutine to follow the target object. /// public void Follow() { if (TrackingObject != null && RootObject != null) { followingTargetObject = true; StartCoroutine(FollowSequence()); } } private IEnumerator FollowSequence() { while (followingTargetObject) { relativePositionTrackingToRoot = GetRelativeLocalPosition(TrackingObject, RootObject); yield return null; } } private Vector3 GetRelativeLocalPosition(GameObject input, GameObject root) { return input.transform.position - root.transform.position; } } }