using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.Events; using UnityEngine.EventSystems; namespace Rokid.MRC { //基类 public abstract class Tweener : MonoBehaviour { static public Tweener current; public enum Direction { eReverse = -1, eToggle = 0, eForward = 1 } public enum Trigger { eOnPointerEnter, eOnPointerDown, eOnPointerClick, eOnPointerUp, eOnPointerExit, None } public enum ShakeType { ePosition, eScale, eRotation } public iTween.EaseType method = iTween.EaseType.linear; public iTween.LoopType style = iTween.LoopType.none; public AnimationCurve animationCurve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 1f), new Keyframe(1f, 1f, 1f, 0f)); public bool ignoreTimeScale = true; public float delay = 0f; public float duration = 1f; public float fixedDelta = 0f; public int tweenGroup = 0; private UnityAction onFinished = null; private UnityAction onValueChange = null; //[HideInInspector] //protected GameObject eventReceiver; //[HideInInspector] //protected string callWhenFinished; private bool mStarted = false; private float mStartTime = 0f; private float mDuration = 0f; private float mAmountPerDelta = 1000f; private float mFactor = 0f; public bool currentDirection { get { return mFactor > 0; } } /// /// Amount advanced per delta time. /// protected float amountPerDelta { get { if(mDuration != duration) { mDuration = duration; mAmountPerDelta = Mathf.Abs((duration > 0f) ? 1f / duration : 1000f) * Mathf.Sign(mAmountPerDelta); } return mAmountPerDelta; } } protected void Reset() { if(!mStarted) { SetStartToCurrentValue(); SetEndToCurrentValue(); } } protected virtual void Start() { Update(); } //实时进行缓动 void Update() { float delta = ignoreTimeScale ? Time.unscaledDeltaTime : Time.deltaTime; float time = ignoreTimeScale ? Time.unscaledTime : Time.time; if(fixedDelta > float.Epsilon) { delta = fixedDelta; } if(!mStarted) { mStarted = true; mStartTime = time + delay; } if(time < mStartTime) return; // Advance the sampling factor mFactor += amountPerDelta * delta; // Loop style simply resets the play factor after it exceeds 1. if(style == iTween.LoopType.loop) { if(mFactor > 1f) { mFactor -= Mathf.Floor(mFactor); } } else if(style == iTween.LoopType.pingPong) { // Ping-pong style reverses the direction if(mFactor > 1f) { mFactor = 1f - (mFactor - Mathf.Floor(mFactor)); mAmountPerDelta = -mAmountPerDelta; } else if(mFactor < 0f) { mFactor = -mFactor; mFactor -= Mathf.Floor(mFactor); mAmountPerDelta = -mAmountPerDelta; } } // If the factor goes out of range and this is a one-time tweening operation, disable the script if((style == iTween.LoopType.none) && (duration == 0f || mFactor > 1f || mFactor < 0f)) { mFactor = Mathf.Clamp01(mFactor); Sample(mFactor, true); enabled = false; if(current != this) { Tweener before = current; current = this; if(onFinished != null) onFinished(); // Deprecated legacy functionality support //if (eventReceiver != null && !string.IsNullOrEmpty(callWhenFinished)) // eventReceiver.SendMessage(callWhenFinished, this, SendMessageOptions.DontRequireReceiver); current = before; } } else Sample(mFactor, false); } public void SetOnFinished(UnityAction finishedCallBack) { onFinished = finishedCallBack; } public void AddOnFinished(UnityAction finishedCallBack) { onFinished += finishedCallBack; } public void RemoveOnFinished(UnityAction finishedCallBack) { if(onFinished != null) onFinished -= finishedCallBack; } void OnDisable() { mStarted = false; } /// /// Sample the tween at the specified factor. /// protected void Sample(float factor, bool isFinished) { // Calculate the sampling value float val = Mathf.Clamp01(factor); val = (method == iTween.EaseType.None) ? animationCurve.Evaluate(val) : iTween.easeValue(method, 0, 1, val); // Call the virtual update OnUpdate((method == iTween.EaseType.None) ? animationCurve.Evaluate(val) : val, isFinished); if(onValueChange != null) { onValueChange.Invoke(); } } /// /// Manually activate the tweening process, reversing it if necessary. /// true Play the tween forward. /// false Play the tween in reverse. /// public void Play(bool forward) { mAmountPerDelta = Mathf.Abs(amountPerDelta); if(!forward) mAmountPerDelta = -mAmountPerDelta; enabled = true; Update(); } /// /// Manually reset the tweener's state to the beginning. /// If the tween is playing forward, this means the tween's start. /// If the tween is playing in reverse, this means the tween's end. /// public void ResetToBeginning() { mStarted = false; mFactor = (amountPerDelta < 0f) ? 1f : 0f; Sample(mFactor, false); } /// /// Manually start the tweening process, reversing its direction. /// public void Toggle() { if(mFactor > 0f) { mAmountPerDelta = -amountPerDelta; } else { mAmountPerDelta = Mathf.Abs(amountPerDelta); } enabled = true; } /// /// Actual tweening logic should go here. /// abstract protected void OnUpdate(float factor, bool isFinished); /// /// Starts the tweening operation. /// static protected T Begin(GameObject go, float duration) where T : Tweener { T comp = go.GetComponent(); #if UNITY_FLASH if ((object)comp == null) comp = (T)go.AddComponent(); #else // Find the tween with an unset group ID (group ID of 0). if(comp != null && comp.tweenGroup != 0) { comp = null; T[] comps = go.GetComponents(); for(int i = 0, imax = comps.Length;i < imax;++i) { comp = comps[i]; if(comp != null && comp.tweenGroup == 0) break; comp = null; } } if(comp == null) { comp = go.AddComponent(); if(comp == null) { Debug.LogError("Unable to add " + typeof(T) + " to " + go); return null; } } #endif comp.mStarted = false; comp.duration = duration; comp.mFactor = 0f; comp.mAmountPerDelta = Mathf.Abs(comp.amountPerDelta); comp.style = iTween.LoopType.none; comp.animationCurve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 1f), new Keyframe(1f, 1f, 1f, 0f)); //comp.eventReceiver = null; //comp.callWhenFinished = null; comp.onFinished = null; comp.enabled = true; return comp; } protected virtual void SetStartToCurrentValue() { } protected virtual void SetEndToCurrentValue() { } protected virtual void SetCurrentValueToStart() { } protected virtual void SetCurrentValueToEnd() { } } }