Newer
Older
HoloAnatomy / Assets / HoloToolkit-Examples / Prototyping / Scripts / ScaleToValue.cs
SURFACEBOOK2\jackwynne on 25 May 2018 6 KB v1
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

namespace HoloToolkit.Examples.Prototyping
{
    /// <summary>
    /// Animates the scaling of an object with eases
    /// </summary>
    public class ScaleToValue : MonoBehaviour
    {
        /// <summary>
        /// ease types
        ///     Linear: steady progress
        ///     EaseIn: ramp up in speed
        ///     EaseOut: ramp down in speed
        ///     EaseInOut: ramp up then down in speed
        ///     Free: super ease - just updates as the TargetValue changes
        /// </summary>
        public enum LerpTypes { Linear, EaseIn, EaseOut, EaseInOut, Free }

        [Tooltip("The object to scale")]
        public GameObject TargetObject;

        [Tooltip("The scale value to animate to")]
        public Vector3 TargetValue;

        [Tooltip("The ease type")]
        public LerpTypes LerpType;

        [Tooltip("The duration of the scale animation in seconds")]
        public float LerpTime = 1f;

        [Tooltip("Auto start? or status")]
        public bool IsRunning = false;

        [Tooltip("Animation complete!")]
        public UnityEvent OnComplete;

        // animation ticker
        private float mLerpTimeCounter;

        // cached start scale
        private Vector3 mStartValue;

        /// <summary>
        /// get the target object if not set already
        /// Set the cached starting scale
        /// </summary>
        private void Awake()
        {
            if (TargetObject == null)
            {
                TargetObject = this.gameObject;
            }
            mStartValue = GetScale();
        }

        /// <summary>
        /// Start the animation
        /// </summary>
        public void StartRunning()
        {
            if (TargetObject == null)
            {
                TargetObject = this.gameObject;
            }

            mStartValue = GetScale();
            mLerpTimeCounter = 0;
            IsRunning = true;
        }

        /// <summary>
        /// reset the scale value to the cached starting value
        /// </summary>
        public void ResetTransform()
        {
            this.transform.localScale = mStartValue;
            IsRunning = false;
            mLerpTimeCounter = 0;
        }

        /// <summary>
        /// Reverse the scale animation for a ping pong effect
        /// </summary>
        public void Reverse()
        {
            TargetValue = mStartValue;
            mStartValue = TargetValue;
            mLerpTimeCounter = 0;
            IsRunning = true;
        }

        /// <summary>
        /// stop the animation
        /// </summary>
        public void StopRunning()
        {
            IsRunning = false;
        }

        /// <summary>
        /// get the current scale
        /// </summary>
        /// <returns></returns>
        private Vector3 GetScale()
        {
            return TargetObject.transform.localScale;
        }

        /// <summary>
        /// get the new scale based on time and ease settings
        /// </summary>
        /// <param name="currentScale"></param>
        /// <param name="percent"></param>
        /// <returns></returns>
        private Vector3 GetNewScale(Vector3 currentScale, float percent)
        {
            Vector3 newScale = Vector3.one;
            switch (LerpType)
            {
                case LerpTypes.Linear:
                    newScale = Vector3.Lerp(mStartValue, TargetValue, percent);
                    break;
                case LerpTypes.EaseIn:
                    newScale = Vector3.Lerp(mStartValue, TargetValue, QuadEaseIn(0, 1, percent));
                    break;
                case LerpTypes.EaseOut:
                    newScale = Vector3.Lerp(mStartValue, TargetValue, QuadEaseOut(0, 1, percent));
                    break;
                case LerpTypes.EaseInOut:
                    newScale = Vector3.Lerp(mStartValue, TargetValue, QuadEaseInOut(0, 1, percent));
                    break;
                case LerpTypes.Free:
                    newScale = Vector3.Lerp(currentScale, TargetValue, percent);
                    break;
                default:
                    break;
            }

            return newScale;
        }

        // ease curves
        public static float QuadEaseIn(float s, float e, float v)
        {
            return e * (v /= 1) * v + s;
        }

        public static float QuadEaseOut(float s, float e, float v)
        {
            return -e * (v /= 1) * (v - 2) + s;
        }

        public static float QuadEaseInOut(float s, float e, float v)
        {
            if ((v /= 0.5f) < 1)
                return e / 2 * v * v + s;

            return -e / 2 * ((--v) * (v - 2) - 1) + s;
        }

        /// <summary>
        /// Animate!
        /// </summary>
        private void Update()
        {
            if (IsRunning && LerpType != LerpTypes.Free)
            {
                // get the time
                mLerpTimeCounter += Time.deltaTime;
                float percent = mLerpTimeCounter / LerpTime;

                // set the scale
                this.transform.localScale = GetNewScale(this.transform.localScale, percent);

                // fire the event if complete
                if (percent >= 1)
                {
                    IsRunning = false;
                    OnComplete.Invoke();
                }
            }
            else if (LerpType == LerpTypes.Free)
            {
                bool wasRunning = IsRunning;

                // set the scale
                this.transform.localScale = GetNewScale(this.transform.localScale, LerpTime * Time.deltaTime);
                IsRunning = this.transform.localScale != TargetValue;

                // fire the event if complete
                if (IsRunning != wasRunning && !IsRunning)
                {
                    OnComplete.Invoke();
                }
            }
        }
    }
}