bo-s
5/20/2014 - 7:50 AM

CoroutineTween.cs

CoroutineTween.cs

/*
 * This code is provided as is without warranty, guarantee of function, 
 * or provided support
 */

using System.Collections;
using UnityEngine.Events;

namespace UnityEngine.UI.CoroutineTween
{
	// Base interface for tweeners, 
	// using an interface instead of 
	// an abstract class as we want the
	// tweens to be structs.
	internal interface ITweenValue
	{
		void TweenValue(float floatPercentage);
		bool ignoreTimeScale { get; }
		float duration { get; }
		bool ValidTarget();
	}

	// Color tween class, receives the
	// TweenValue callback and then sets
	// the value on the target.
	internal struct ColorTween : ITweenValue
	{
		public enum ColorTweenMode
		{
			All,
			RGB,
			Alpha
		}

		public class ColorTweenCallback : UnityEvent<Color> {}

		private ColorTweenCallback m_Target;
		private Color m_StartColor;
		private Color m_TargetColor;
		private ColorTweenMode m_TweenMode;

		private float m_Duration;
		private bool m_IgnoreTimeScale;

		public Color startColor
		{
			get { return m_StartColor; }
			set { m_StartColor = value; }
		}

		public Color targetColor
		{
			get { return m_TargetColor; }
			set { m_TargetColor = value; }
		}

		public ColorTweenMode tweenMode
		{
			get { return m_TweenMode; }
			set { m_TweenMode = value; }
		}

		public float duration
		{
			get { return m_Duration; }
			set { m_Duration = value; }
		}

		public bool ignoreTimeScale
		{
			get { return m_IgnoreTimeScale; }
			set { m_IgnoreTimeScale = value; }
		}

		public void TweenValue(float floatPercentage)
		{
			if (!ValidTarget())
				return;

			var newColor = Color.Lerp (m_StartColor, m_TargetColor, floatPercentage);

			if (m_TweenMode == ColorTweenMode.Alpha)
			{
				newColor.r = m_StartColor.r;
				newColor.g = m_StartColor.g;
				newColor.b = m_StartColor.b;
			}
			else if (m_TweenMode == ColorTweenMode.RGB)
			{
				newColor.a = m_StartColor.a;
			}
			m_Target.Invoke (newColor);
		}

		public void AddOnChangedCallback(UnityAction<Color> callback)
		{
			if (m_Target == null)
				m_Target = new ColorTweenCallback();

			m_Target.AddListener (callback);
		}

		public bool GetIgnoreTimescale()
		{
			return m_IgnoreTimeScale;
		}

		public float GetDuration()
		{
			return m_Duration;
		}

		public bool ValidTarget()
		{
			return m_Target != null;
		}
	}

	// Tween runner, executes the given tween.
	// The coroutine will live within the given 
	// behaviour container.
	internal class TweenRunner<T> where T : struct, ITweenValue
	{
		protected MonoBehaviour m_CoroutineContainer;
		protected IEnumerator m_Tween;

		// utility function for starting the tween
		private static IEnumerator Start(T tweenInfo)
		{
			if (!tweenInfo.ValidTarget())
				yield break;

			var elapsedTime = 0.0f;
			while (elapsedTime < tweenInfo.duration)
			{
				elapsedTime += tweenInfo.ignoreTimeScale ? Time.unscaledDeltaTime : Time.deltaTime;
				var percentage = Mathf.Clamp01 (elapsedTime / tweenInfo.duration);
				tweenInfo.TweenValue (percentage);
				yield return null;
			}
			tweenInfo.TweenValue (1.0f);
		}

		public void Init(MonoBehaviour coroutineContainer)
		{
			m_CoroutineContainer = coroutineContainer;
		}

		public void StartTween(T info)
		{
			if (m_CoroutineContainer == null)
			{
				Debug.LogWarning ("Coroutine container not configured... did you forget to call Init?");
				return;
			}

			if (m_Tween != null)
			{
				m_CoroutineContainer.StopCoroutine (m_Tween);
				m_Tween = null;
			}

			if (!m_CoroutineContainer.gameObject.activeInHierarchy)
			{
				info.TweenValue(1.0f);
				return;
			}

			m_Tween = Start (info);
			m_CoroutineContainer.StartCoroutine (m_Tween);
		}
	}
}