国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

NGUI源碼剖析——動畫(UITweener)

2019-11-09 17:37:37
字體:
來源:轉載
供稿:網友

查NGUI動畫方面的資料時,發現D.S.Qiu寫的一篇UITweener源碼剖析的blog,源碼面前了無秘密,原文鏈接。另外,D.S.Qiu寫過一系列NGUI源碼的blog,值得每個使用NGUI的研讀。

NGUI所見即所得之UITweener

        一直沒有用過NGUI動畫的功能,之前的理解就是:設置始末兩個“位置”,然后就是從起始位置移到結束位置。至于中間是怎么變化的,就感覺很神奇了,變化率怎么設置才不會看起來很“傻”,這里不是看“郭靖”,動畫一定要有驚奇,摸不著猜不透的感覺。對NGUI主要的幾個腳本都已經有點掌握了(猛點查看),一直都沒有去”膜拜“Tweening文件夾的各個大神,可能以前會覺得不就是一個動畫組件,自己都可以實現。但是看過里面的代碼就后悔了,因為至少結合TweenFOV和TweenOrhoSize這兩個腳本就可以實現很多效果,竟然輕而易舉的集成了,看來人還是不要太看得起自己的好,這樣才會走的更快更遠。

        每次都覺得前面吹水很寫,也寫不好(一直都有感覺自己的寫作水平太差了),那就來看下Tweening文件夾下到底賣的是什么藥——UITweener和它的“孩子”: 

UITweener的Fields        看著很復雜,其實只要把UITweener琢磨透了,其它都只是重寫UITweener的OnUpdate方法和封裝了Begin方法。還是先看下主要的Field(作用看注釋):

C#代碼  收藏代碼       bool mStarted = false;  //是否開始動畫  float mStartTime = 0f;   //動畫開始播放的時間, mStarted =true;mStartTime = time + delay;  float mDuration = 0f;    //動畫長度(時間)  float mAmountPerDelta = 1000f;   //單位時間動畫播放的長度,有點幀率的感覺  float mFactor = 0f;           //當前動畫播放的進度    /// <summary>  /// Amount advanced per delta time.  /// </summary>    public float amountPerDelta  {      get      {          if (mDuration != duration)          {              mDuration = duration;              mAmountPerDelta = Mathf.Abs((duration > 0f) ? 1f / duration : 1000f);          }          return mAmountPerDelta;      }  }  

        通過Begin設置需要的參數:

C#代碼  收藏代碼       static public T Begin<T> (GameObject go, float duration) where T : UITweener  {      T comp = go.GetComponent<T>();  if UNITY_Flash      if ((object)comp == null) comp = (T)go.AddComponent<T>();  else      if (comp == null) comp = go.AddComponent<T>();  endif      comp.mStarted = false;      comp.duration = duration;      comp.mFactor = 0f;      comp.mAmountPerDelta = Mathf.Abs(comp.mAmountPerDelta);      comp.style = Style.Once;      comp.animationCurve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 1f), new Keyframe(1f, 1f, 1f, 0f));      comp.eventReceiver = null;      comp.callWhenFinished = null;      comp.enabled = true;      return comp;  }  

Update函數     

然后再Update函數先計算出時間delta,進一步計算出當前動畫播放的mFactor,然后進行Sample采用,執行OnUpdate:

C#代碼  收藏代碼void Update ()  {      float delta = ignoreTimeScale ? RealTime.deltaTime : Time.deltaTime;      float time = ignoreTimeScale ? RealTime.time : Time.time;        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 == Style.Loop)      {          if (mFactor > 1f)          {              mFactor -= Mathf.Floor(mFactor);          }      }      else if (style == Style.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 == Style.Once) && (mFactor > 1f || mFactor < 0f))      {          mFactor = Mathf.Clamp01(mFactor);          Sample(mFactor, true);            current = this;            // Notify the listener delegates          EventDelegate.Execute(onFinished);            // DePRecated legacy functionality support          if (eventReceiver != null && !string.IsNullOrEmpty(callWhenFinished))              eventReceiver.SendMessage(callWhenFinished, this, SendMessageOptions.DontRequireReceiver);            current = null;            // Disable this script unless the function calls above changed something          if (mFactor == 1f && mAmountPerDelta > 0f || mFactor == 0f && mAmountPerDelta < 0f)              enabled = false;      }      else Sample(mFactor, false);  }  

 Sample采樣函數

        前面說的動畫要有摸不著猜不透的感覺,就是要考Sample的采樣函數來實現的,UITweener支持5種動畫曲線:

C#代碼  收藏代碼       public enum Method  {      Linear,      EaseIn,      EaSEOut,      EaseInOut,      BounceIn,      BounceOut,  }  

 采樣的函數,原理很簡單:根據當前播放的進度mFactor,計算出實際的動畫播放刻度,然后執行OnUpdate操作:

C#代碼  收藏代碼public void Sample (float factor, bool isFinished)  {      // Calculate the sampling value      float val = Mathf.Clamp01(factor);        if (method == Method.EaseIn)      {          val = 1f - Mathf.Sin(0.5f * Mathf.PI * (1f - val));          if (steeperCurves) val *= val;      }      else if (method == Method.EaseOut)      {          val = Mathf.Sin(0.5f * Mathf.PI * val);            if (steeperCurves)          {              val = 1f - val;              val = 1f - val * val;          }      }      else if (method == Method.EaseInOut)      {          const float pi2 = Mathf.PI * 2f;          val = val - Mathf.Sin(val * pi2) / pi2;            if (steeperCurves)          {              val = val * 2f - 1f;              float sign = Mathf.Sign(val);              val = 1f - Mathf.Abs(val);              val = 1f - val * val;              val = sign * val * 0.5f + 0.5f;          }      }      else if (method == Method.BounceIn)      {          val = BounceLogic(val);      }      else if (method == Method.BounceOut)      {          val = 1f - BounceLogic(1f - val);      }        // Call the virtual update      OnUpdate((animationCurve != null) ? animationCurve.Evaluate(val) : val, isFinished);  }  

 緩動函數(easing fuction)

        上面說的動畫曲線,中文叫緩動函數(曲線):        通過上面這張圖可以很感性的認識不同函數的具體的效果,也可以自己嘗試推導一邊加深理解,不過D.S.Qiu已經有點“廉頗老矣”,憑著記憶“奇變偶不變,符號看象限”,慢的只能到easeInSine,要想詳細了解可以參考②和③。

 

妙用mAmountPerDelta

         mAmountPerDelta就是動畫播放速度,只對mAmountPerData就可以有更多控制:Toggle,PlayForward,PlayResverse:

C#代碼  收藏代碼/// <summary>  /// Manually activate the tweening process, reversing it if necessary.  /// </summary>    public void Play (bool forward)  {      mAmountPerDelta = Mathf.Abs(amountPerDelta);      if (!forward) mAmountPerDelta = -mAmountPerDelta;      enabled = true;      Update();  }  /// <summary>  /// Manually start the tweening process, reversing its direction.  /// </summary>    public void Toggle ()  {      if (mFactor > 0f)      {          mAmountPerDelta = -amountPerDelta;      }      else      {          mAmountPerDelta = Mathf.Abs(amountPerDelta);      }      enabled = true;  }  

 

『Bug修復和吐槽

        之前用TweenRotation這個腳本,做游戲等待轉圈等待界面,發現總是不能旋轉360度,總是一個小于180的角度,無論from和to如何設置:

C#代碼  收藏代碼public Vector3 from;  public Vector3 to;  

 后來無奈之下,只好去看下TweenRotation的OnUpdate函數,發現使用的是 Quaternion.Slerp這個函數,發現確實是這樣,所以就做了下面的修改:

C#代碼  收藏代碼protected override void OnUpdate (float factor, bool isFinished)  {      //cachedTransform.localRotation = Quaternion.Slerp(Quaternion.Euler(from), Quaternion.Euler(to), factor);      //NGUI的實現是上一行,有Bug,不能達到要求      cachedTransform.localEulerAngles = Vector3.Lerp(from, to, factor);    }  

 

       NGUI提供了UIPlayTween,這個腳本管理一組Tween腳本的Play,提供了不同的Tirgger,然后在不同的事件函數中觸發Play(true):

C#代碼  收藏代碼void OnClick ()  {      if (enabled && trigger == Trigger.OnClick)      {          Play(true);      }  }  

       雖然UIPlayTween提供了很多參數都是沒有滿足要其交替地進行PlayForward和PlayReverse,因為其都是執行Play(true),開始的時候我想到了給其中一個UITween添加OnFinished委托,在播放結束的時候改變playDiretion的方向:

C#代碼  收藏代碼public Direction playDirection = Direction.Forward;  

       但是這個控制因為動畫是有時間的,會有問題。所以我只能添加一個Trigger的類型:Trigger.None,然后自己去調用,就是自己管理動畫的播放,而不是在OnClick中觸發。』

                                                                                           增補于 2013,12,23  21:50

小結:

       確實很簡單,主要是對緩動函數的理解,有了這些基礎可以做的事情(特效和動畫)就很多了——屏幕抖動和刀光劍影(下次自己動手嘗試下,哈哈),NGUI的ButtonScale等腳本也是通過UITweener來完成的。但是收獲蠻多的,又一點多了,晚安!

參考:

①NGUI: Next-Gen UI kit  3.0.0:http://www.tasharen.com/ngui/docs/class_u_i_tweener.html

② 緩動函數:http://easings.net/zh-cn

③Easing Equations by Robbert Penner: http://www.gizma.com/easing/#sin2

④Unity3dPack: http://www.unity3dpack.com/?p=300


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 西充县| 泰顺县| 高雄县| 屏南县| 柳州市| 岢岚县| 内黄县| 长治县| 台南县| 福安市| 宾川县| 兴山县| 文安县| 卫辉市| 太仓市| 惠来县| 兴业县| 衡阳市| 睢宁县| 青阳县| 开原市| 垦利县| 万荣县| 台东县| 枣强县| 苍山县| 达孜县| 易门县| 吴堡县| 苏州市| 都安| 本溪市| 遂平县| 丰台区| 北票市| 杂多县| 菏泽市| 浦北县| 正蓝旗| 兴国县| 临高县|