看板 GameDesign 關於我們 聯絡資訊
圖文版 http://goo.gl/bbpiJ 在製作遊戲的時候,動畫是不可或缺的一部份,即使是與遊戲核心無關的 GUI 部份,若少了動畫就顯得粗製濫造。然而大多數的 GUI 效果:像是視窗飛進 畫面中央、按下按鈕時放大效果之類的動畫等等,其內容都有很高的相似性, 也就是「在某段時間內,把物件的某些狀態轉移到另一個狀態」。若要使用 3D Max 之類的軟體一一製作,將顯得麻煩而沒有效率。 在這篇文章中,我會以 Unity 作為範例,介紹如何實作一個簡單的 easing function 元件。 範例需求 想像一下我們正在製作遊戲過程中的暫停選單。當玩家按下暫停鈕時,畫面上 會出現暫停的面板以及三個按鈕。當然,直接讓它們出現是很粗糙的作法,因 此我們希望面板及按鈕可以從畫面外飛進來。 使用線性內插 最簡單的呈現方式是使用線性內插法,指定好某個物件的起始狀態(位置、大 小、顏色等)與結束狀態,再指定動畫時間。只要有了這些資訊,我們可以用 簡單的數學運算內插出動畫播放時每一格 frame 的物件狀態。 using UnityEngine; using System; public class EasingDemo : MonoBehaviour { public Vector3 destination; public float duration = 1; public float delay = 0; private Vector3 source; private Vector3 delta; private float elapsed = 0; void Start() { source = transform.position; delta = destination - source; } void Update() { elapsed += Time.deltaTime; if(elapsed > delay && elapsed < (delay+duration)){ float ratio = Math.Min(1, (elapsed-delay)/duration); transform.position = source + ratio*delta; } } } 這個簡單的元件讓我們可以在 Unity 編輯器中直接設定物件的起始位置、結 束位置及動畫播放的時間。接下來,我們把面板與按鈕放在鏡頭外面,然後把 它的結束位置設定在畫面內,按下 play 後馬上可以看到它的效果……非常地 普通 XD http://youtu.be/h8KI88Tx_eQ
這個動畫之所以看起來很無聊,大部份的原因在於我們使用了很無聊的線性內 插法。想像一下如果這個按鈕是用以下的方式飛進畫面: * 很快地衝進來,然後緊急剎車停在目的地。 * 衝過頭然後拉回目的地。 * 撞到目的地後像皮球般反彈,最後再落回目的地。 這樣的動畫,顯然會比死板的等速度飛入更活潑、更有動感。然而製作這種動 畫效果就沒辦法用線性內插了。當然,若使用 3D Max 就可以藉由貝茲曲線 (Bézier curve) 來編輯這種較複雜的動畫,或是直接用 Unity 的動畫編輯器 也能辦到。然而編輯貝玆曲線的各個控制點卻是一件很花時間的工作,尤其像 第三個例子,為了達到反彈的效果,我們得額外加入兩三個 key frame 才行。 過程並不是很難,但就是很花時間。 使用 Unity 動畫編輯器的情況: http://goo.gl/RaEqu 使用非線性內插法 我們不希望動畫是平板的線性內插法,但又覺得編輯貝茲曲線的控制點太麻煩, 那麼答案就呼之欲出了:使用其它的數學曲線來代替直線。比如說如下的曲線: http://goo.gl/egaW6 儘管物理上並不正確,但它看起來就像是「很快地衝進來,然後緊急剎車」的 樣子。因此我們可以把它套用到內插計算式中: void Update() { elapsed += Time.deltaTime; if(elapsed > delay && elapsed < (delay+duration)){ float x = Math.Min(1, (elapsed-delay)/duration); float ratio = (float)Math.Pow(x-1, 3) + 1; transform.position = source + ratio*delta; } } 結果如下,同樣都是一秒鐘的動畫,感覺起來是不是有微妙的差異呢? http://youtu.be/UOIB7z220tw
Easing Function 慣例格式 Easing function 具有一項優勢:只要抽換不同的 easing function,不需要 另外編輯 key frame 或是曲線控制點,就馬上可以得到另一種動畫。但為了達 到這個「可抽換」的目的,我們得要使用大家所慣用的寫法: public class Easing { public static float Linear(float t, float b, float c, float d) { return c*(t/d) + b; } public static float OutCubic(float t, float b, float c, float d) { t /= d; t--; return c*(t*t*t+1)+b; } } 一般化的 easing function 有四個參數: * t (time): 代表動畫開始播放到現在所經過的時間。 * b (beginning): 代表某項屬性的初始值。 * c (change): 代表到動畫結束時,該屬性的變化值。亦即動畫結束後,這項屬 性的值應為 b+c。 * d (duration): 代表整段動畫的播放時間。 因此我們可以改寫原本的 Update(): public delegate float EasingFunction(float t, float b, float c, float d); EasingFunction easing = new EasingFunction(Easing.OutCubic); void Update() { elapsed += Time.deltaTime; if(elapsed > delay && elapsed < (delay+duration)){ Vector3 p = new Vector3(); float t = elapsed - delay; p.x = easing(t, source.x, delta.x, duration); p.y = easing(t, source.y, delta.y, duration); p.z = easing(t, source.z, delta.z, duration); transform.position = p; } } 這麼一來,我們就可以利用別人寫好的 easing function 套用到我們的動畫元 件中。事不遲疑,馬上就來看看範例。 彈跳動畫 上述「像是皮球般地彈跳」顯然是一種很困難的曲線,但早就有人寫好了它的 easing function,只要 google 一下馬上就能找到如下的程式碼: public static float Bounce(float t, float b, float c, float d) { if ((t /= d) < (1.0f / 2.75)) { return c * (7.5625f * t * t) + b; } else if (t < (2.0f / 2.75)) { return c * (7.5625f * (t-=(1.5f/2.75f)) * t + 0.75f) + b; } else if (t < (2.5f / 2.75)) { return c * (7.5625f * (t-=(2.25f/2.75f)) * t + 0.9375f) + b; } else { return c * (7.5625f * (t-=(2.625f/2.75f)) * t + 0.984375f) + b; } } 然後我們把 EasingDemo 中的 easing function 設定為 Easing.Bounce,馬上 就能看到彈跳的面板與按鈕: http://youtu.be/ZVZcXKFhGZw
這樣的效果是不是比前面慢慢飛進來的動畫要生動許多呢? 結語及參考資源 只要指定起始狀態、結束狀態、播放時間及 easing function 的種類,即可組合 出千變萬化的各種效果,因此 easing function 是相當廣泛的 2D 動畫技術。知 名的 JavaScript 函式庫 jQuery 也內建了許多不同種類的 easing function, 可以在 [http://goo.gl/zwkrq] 看到它們的效果。 Tim Groleau 的 easing function 產生器 [http://goo.gl/rpqFP] 則是一個幫 你產生程式碼的工具。你可以藉由拖拉控制點的方式編輯出你想要的曲線形式, 然後旁邊就會出現這個 easing function 的 JavaScript 程式碼。這個工具也事 先寫好了許多常用的 easing function 讓你可以直接利用。 最後,這篇教學的 Unity 範例場景可以在 [http://goo.gl/Xq9e5] 下載。只要 開一個新的 Unity 專案並選擇匯入套件,即可看到範例程式碼及實際的動畫效果。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 202.39.238.241
Transformers:推 分享 09/16 21:50
a83a83cjcj:實用推 09/16 22:25
tsl3333:推!!! 09/16 22:55