/****************************************************************************** * Copyright (C) Ultraleap, Inc. 2011-2021. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * * between Ultraleap and you, your company or other organization. * ******************************************************************************/ using Leap.Unity.Attributes; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; namespace Leap.Unity.Animation { /// /// This is a wrapper MonoBehaviour that demonstrates and exposes some of the /// basic functionality of the Tween library. Tweens can interpolate between /// more than just Transform properties, so don't be afraid to roll your own. /// public class TransformTweenBehaviour : MonoBehaviour { [Tooltip("The transform to which to apply the tweened properties.")] public Transform targetTransform; [Tooltip("The transform whose position/rotation/localScale provide the start state of the tween.")] public Transform startTransform; [Tooltip("The transform whose position/rotation/localScale provide the end state of the tween.")] public Transform endTransform; public bool startAtEnd = false; [Header("Tween Settings")] public bool tweenLocalPosition = true; public bool tweenLocalRotation = true; public bool tweenLocalScale = true; [MinValue(0.001F)] public float tweenDuration = 0.25F; public SmoothType tweenSmoothType = SmoothType.Smooth; #region Events public Action OnProgress = (progress) => { }; public Action OnLeaveStart = () => { }; public Action OnReachEnd = () => { }; public Action OnLeaveEnd = () => { }; public Action OnReachStart = () => { }; #endregion private Tween _tween; /// /// Returns the Tween object the TransformTween behaviour produces on Start(). /// /// Use this to play or otherwise manipulate the animation. /// public Tween tween { get { return _tween; } set { _tween = value; } } void OnValidate() { if (targetTransform != null) { if (startTransform == targetTransform) { Debug.LogError("The start transform of the TransformTweenBehaviour should be " + "a different transform than the target transform; the start " + "transform provides starting position/rotation/scale information " + "for the tween.", this.gameObject); } else if (endTransform == targetTransform) { Debug.LogError("The end transform of the TransformTweenBehaviour should be " + "a different transform than the target transform; the end " + "transform provides ending position/rotation/scale information " + "for the tween.", this.gameObject); } } } void Awake() { initUnityEvents(); // Tween setup methods return the Tween object itself, so you can chain your setup // method calls. _tween = Tween.Persistent().OverTime(tweenDuration) .Smooth(tweenSmoothType); if (tweenLocalPosition) _tween = _tween.Target(targetTransform) .LocalPosition(startTransform, endTransform); if (tweenLocalRotation) _tween = _tween.Target(targetTransform) .LocalRotation(startTransform, endTransform); if (tweenLocalScale) _tween = _tween.Target(targetTransform) .LocalScale(startTransform, endTransform); // Hook up the UnityEvents to the actual Tween callbacks. _tween.OnProgress(OnProgress); _tween.OnLeaveStart(OnLeaveStart); _tween.OnReachEnd(OnReachEnd); _tween.OnLeaveEnd(OnLeaveEnd); _tween.OnReachStart(OnReachStart); // TODO: This isn't great but it's the only way I've seen to make sure the tween // updates with its progress at the right state :( if (startAtEnd) { _tween.progress = 0.9999999F; _tween.Play(Direction.Forward); } else { _tween.progress = 0.0000001F; _tween.Play(Direction.Backward); } } void OnDestroy() { if (_tween.isValid) { _tween.Release(); } } private Coroutine _playTweenAfterDelayCoroutine; private Direction _curDelayedDirection = Direction.Backward; /// /// Tweens play forward by default, but at any time past the starting /// state they can also be played backwards to return to the starting /// state. See the tween property for more direct control of this /// behaviour's tween. /// public void PlayTween() { PlayTween(Direction.Forward); } public void PlayTween(Direction tweenDirection = Direction.Forward, float afterDelay = 0F) { if (_playTweenAfterDelayCoroutine != null && tweenDirection != _curDelayedDirection) { StopCoroutine(_playTweenAfterDelayCoroutine); _curDelayedDirection = tweenDirection; } _playTweenAfterDelayCoroutine = StartCoroutine(playAfterDelay(tweenDirection, afterDelay)); } private IEnumerator playAfterDelay(Direction tweenDirection, float delay) { yield return new WaitForSeconds(delay); tween.Play(tweenDirection); } public void PlayForward() { PlayTween(Direction.Forward); } public void PlayBackward() { PlayTween(Direction.Backward); } public void PlayForwardAfterDelay(float delay = 0F) { PlayTween(Direction.Forward, delay); } public void PlayBackwardAfterDelay(float delay = 0F) { PlayTween(Direction.Backward, delay); } /// /// Stops the underlying tween and resets it to the starting state. /// public void StopTween() { tween.Stop(); } public void SetTargetToStart() { setTargetTo(startTransform); } public void SetTargetToEnd() { setTargetTo(endTransform); } private void setTargetTo(Transform t) { if (targetTransform != null && t != null) { if (tweenLocalPosition) targetTransform.localPosition = t.localPosition; if (tweenLocalRotation) targetTransform.localRotation = t.localRotation; if (tweenLocalScale) targetTransform.localScale = t.localScale; } } #region Unity Events (Internal) [System.Serializable] public class FloatEvent : UnityEvent { } #pragma warning disable 0649 [SerializeField] private EnumEventTable _eventTable; #pragma warning restore 0649 public enum EventType { //OnProgress = 100, // Requires float Event data OnLeaveStart = 110, OnReachEnd = 120, OnLeaveEnd = 130, OnReachStart = 140 } private void initUnityEvents() { setupCallback(ref OnLeaveStart, EventType.OnLeaveStart); setupCallback(ref OnReachEnd, EventType.OnReachEnd); setupCallback(ref OnLeaveEnd, EventType.OnLeaveEnd); setupCallback(ref OnReachStart, EventType.OnReachStart); } private void setupCallback(ref Action action, EventType type) { action += () => _eventTable.Invoke((int)type); } private void setupCallback(ref Action action, EventType type) { action += (anchObj) => _eventTable.Invoke((int)type); } #endregion } }