using System.Collections; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.UI.HandCoach { /// /// This class provides functionality to rotate the hand hint around a pivot point over time. /// public class RotateAroundPoint : MonoBehaviour { [Tooltip("Parent object centered at rotation center.")] [SerializeField] private Transform centeredParent = null; /// /// Parent object centered at rotation center. /// public Transform CenteredParent { get { return centeredParent; } set { centeredParent = value; } } [Tooltip("Hand hint parent to rotate inverse to centeredParent to keep hand orientation the same.")] [SerializeField] private Transform inverseParent = null; /// /// Hand hint parent to rotate inverse to centeredParent to keep hand orientation the same. /// public Transform InverseParent { get { return inverseParent; } set { inverseParent = value; } } [Tooltip("Point to start movement at.")] [SerializeField] private Transform pivotPosition = null; /// /// Point to start movement at. /// public Transform PivotPosition { get { return pivotPosition; } set { pivotPosition = value; } } [Tooltip("Duration of rotation around the CenteredParent in seconds.")] [SerializeField] private float duration = 1.38f; /// /// Duration of rotation around the CenteredParent in seconds. /// public float Duration { get { return duration; } set { duration = value; } } [Tooltip("Lerp curve that controls the animation rotation over time.")] [SerializeField] private AnimationCurve animationCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f); /// /// Lerp curve that controls the animation rotation over time. /// public AnimationCurve AnimationCurve { get { return animationCurve; } set { animationCurve = value; } } [Tooltip("How many degrees to rotate along each axis.")] [SerializeField] private Vector3 rotationVector = new Vector3(0f, 90f, 0f); /// /// How many degrees to rotate along each axis. /// public Vector3 RotationVector { get { return rotationVector; } set { rotationVector = value; } } private Vector3 centeredParentRotate; private Vector3 hintPosition; // used to allow position changing in LateUpdate() and position correction in RotateHintSequence() private bool updatePosition = true; // since this script can attach to an object with an animator, we need to update position in LateUpdate public void LateUpdate() { // set inverseParent position based on DeterminePivot() if (updatePosition) { InverseParent.localPosition = hintPosition; } // set centeredParent rotation based on RotateToTarget() CenteredParent.localEulerAngles = centeredParentRotate; // set inverseParent rotation based on RotateToTarget() and parent object InverseParent.localEulerAngles = -centeredParentRotate; } /// /// Start the rotation sequence. /// public void RotateToTarget() { StartCoroutine(RotateHintSequence()); } /// /// Reset position to the PivotPosition. /// public IEnumerator ResetAndDeterminePivot() { // reset rotation and wait a frame to ensure the centeredParent is set in LateUpdate centeredParentRotate = new Vector3(0f, 0f, 0f); yield return null; int index = 0; updatePosition = true; StartCoroutine(TrackPositionSequence(index)); } // tracks the pivot determined above private IEnumerator TrackPositionSequence(int index) { while (updatePosition) { hintPosition = PivotPosition.localPosition; yield return null; } } // lerp from current position to target position private IEnumerator RotateHintSequence() { updatePosition = false; Vector3 centeredOrigin = CenteredParent.localEulerAngles; Vector3 targetOrigin = centeredOrigin + RotationVector; float t = 0; while (t <= Duration) { centeredParentRotate = Vector3.Lerp(centeredOrigin, targetOrigin, AnimationCurve.Evaluate(t / duration)); t += Time.deltaTime; yield return null; } // after we reach the target, we still want to be stabilized while (!updatePosition) { centeredParentRotate = targetOrigin; yield return null; } } } }