iT邦幫忙

2023 iThome 鐵人賽

DAY 23
1
Modern Web

什麼!在網頁上也可以寫遊戲?系列 第 23

[Day 23] 射飛鏢實作篇-飛鏢投擲動畫、Easing 函數(補間動畫)

  • 分享至 

  • xImage
  •  

繼昨天的鼠標浮動飛鏢,以及計算飛鏢目的地後,我們今天要來讓飛鏢具有飛行的動畫效果,那就開始吧!

補間動畫

打開昨天設置飛鏢目的地的 更新顯示物件,裡面有一個 設定補間動畫,可以利用 Easing 函數,讓我們將時間以一個數學式關聯到物件的某個屬性上,藉此來產生動畫效果,聽起來好像很複雜,先來看看動作內的設定如何。

補間動畫也算是一種物件,所以同樣可以為其命名一個 ID,其他則是代表動畫的效果以及動畫時間。

目前 補間方式 的所有種類如下:

  • Linear:線性函數
  • Quadratic:二次函數
  • Cubic:三次函數
  • Quartic:四次函數
  • Quintic:五次函數
  • Sinusoidal:正弦函數
  • Exponential:指數函數
  • Circular:圓形函數
  • Elastic:彈性函數
  • Back:回彈函數
  • Bounce:彈跳函數

補間時機 則有:

  • In:淡入
  • InOut:淡入淡出
  • Out:淡出

其中補間方式除了 Linear 以外,其他都可以與補間時機搭配出不同的動畫效果,因為 Linear 就只是一條直線而已,而關於 Easing 函數詳細的原理我就不多嘴了,因為我頂多只能說是會用,要能夠講解就不太有把握了,所以下面這裡我提供了一些推薦的連結,以及 CG 使用 Easing 函數的原始函示庫給各位參考。

小哈的教學影片:數學妹子與遊戲漢子的相遇: (科普)Easing函式將遊戲可愛化了
Easing 函數小抄:easings.net
Easing 函數的函式庫:tween.js

各位可以自行嘗試各種不同的補間方式和時機,來決定自己想要的動畫過程,我個人是選擇 Quintic Out(五次方淡出),動畫時間則設定為 2000 毫秒,這樣飛鏢飛出的速度感我覺得很棒,動畫 ID 則不用管,因為我們不會需要讀取到這個物件,設定好後儲存動作。

接下來由於 tap_xtap_y 這兩個變數的用途已經結束了,所以我們要來將其刪除,新增兩個動作 刪除全域變數,各自填入這兩個變數名稱即可。

變數刪除後,接下來我們要等到飛鏢停止運動後將飛鏢移除,不過由於五次方淡出的關係,所以飛鏢大概在 1000 毫秒之後就沒什麼動力了,如果不是選擇五次方淡出的話,可能就要另外測試適合的等待時間了,總之我們新增動作 等待,時間設為 1000 毫秒,接著新增動作 移除物件物件ID 選擇 dart* 用來將其移除。

設定好後就可以測試遊戲看看了,這時應該就可以正常的投擲飛鏢了,且飛鏢在即將停止前就會被移除,是不是很酷呢?

雖然可以投擲飛鏢了,但飛鏢一點轉動的痕跡都沒有,看起來很無趣,所以我們要來讓飛鏢飛出時會跟著轉動。

投擲會轉動的飛鏢

還記得我們前天介紹轉動飛鏢時所說的嗎?要設置飛鏢的轉動必須單獨調整本體與陰影的角度,因此我們要來重複這個步驟。

新增動作 更新顯示物件,先選擇 dart*.dart_clip*,由於這次飛鏢的轉動動畫是需要 補間動畫 來完成,所以我們要將其設定成和飛出飛鏢的補間動畫相同,接著勾選 設定旋轉角度,然後就是 旋轉角度 究竟該怎麼決定了。

旋轉角度預設是 {this.rotationDeg},代表當前物件自身的角度,所以若是要讓其旋轉,只要以此為基礎,加或減其他數值即可,例如 {this.rotationDeg} + 10 就是讓其順時針轉 10 度,反之負數就是逆時針。

數學還不錯的人會發現,在這裡角度的方向與一般數學所學到的不同,因為一般數學中的座標平面,向上是 y 會越大,向下則越小,所以角度從 0 開始增加時也是向上移動(逆時針),但在電腦的世界中,原點 (0,0) 是畫面的左上角,往右同樣是 x 越大,但往下就變成 y 越大了,因此在這裡角度的變化,從 0 開始增加就會變成向下移動(順時針)。

我們昨天不是已經算出飛鏢飛出的距離了嗎?由於我們的動畫時間是固定的,因此距離越大,代表速度越快,所以某方面來說這個距離也可以代表飛行速度的意思,飛行速度越快,轉動的速度也就越快。

因此我們可以把昨天的算式拿來用,變成如下的算式:

{this.rotationDeg} + sqrt(pow({mouse.x} - {tap_x}, 2) + pow({mouse.y} - {tap_y}, 2))

但只是單純加上鼠標距離的話,轉動速度看起來會過慢,因此與昨天的移動距離一樣,要乘以一個倍數,我自己是將其乘以 2,所以最終的算式如下:

{this.rotationDeg} + sqrt(pow({mouse.x} - {tap_x}, 2) + pow({mouse.y} - {tap_y}, 2)) * 2

完成後可以複製該動作,並將物件 ID 改成 dart*.dart_shadow* 後儲存,然後將剛剛新增的兩個更新顯示物件移到刪除全域變數的上方,不然變數被刪掉後才執行就沒用了。

接著再測試一次,可以看到飛鏢被投擲後已經會自體旋轉了,但此時我們還有一個小細節要添加,那就是如果滑鼠停留在飛鏢上,不斷的點擊飛鏢,由於距離為 0 的關係,此時就會一直生出不會動的飛鏢,為了避免這個問題,我們要來新增一項檢查,那就是判斷玩家的滑鼠在按下之後,鼠標是否有稍微移動過。

最小投擲力道

最簡單的判斷方法就是使用 比較數字 來比較距離,如果移動的距離 > 50 就算通過,這個機制的意思就是當力道太小時,飛鏢會沒辦法投擲,至於距離的計算公式相信不用多說了,我們剛剛已經使用過了,所以設定結果就是 sqrt(pow({mouse.x} - {tap_x}, 2) + pow({mouse.y} - {tap_y}, 2)) > 50,完成後儲存。

還沒完,由於這個檢查的關係,造成我們現在按下飛鏢,放開後可能不會執行事件的緣故,導致儲存滑鼠座標的變數不會被移除,因此這時我們只要輕點一下飛鏢,再點一下上方的空地,就可以投擲飛鏢了,就不是按住飛鏢拖曳後再放開了,所以這個部分也要解決。

這時就是否則觸發事件登場的時候了,當距離檢查不通過時,就觸發其他事件來移除變數,因此我們先新增一個事件 飛鏢投擲失敗,將其設定為 參考事件,並將上方的兩個 刪除全域變數 複製後拖曳下來,事件就設定完了。

回到剛剛的 比較數字 中,將 否則觸發事件ID 設定為 飛鏢投擲失敗 後儲存檢查,如此一來就可以避免上述情況的發生了。

最終 放開飛鏢 事件就如上圖所示,此時最後測試一下,投擲飛鏢的部分已經很完整了,唯一美中不足的地方可能就是飛鏢不會落地,兩年前的我有讓飛鏢落地,但我們已經花很多時間在飛鏢身上了,所以就先到此為止。

最後還有另外一點,在投擲飛鏢後,如果是電腦端的話,應該會發現投擲出去的飛鏢會飛出舞台,繼續在漆黑的深淵中飛行,這似乎有點奇怪,所以明天我們會介紹如何限制物件只顯示在舞台中的方法。

CG 範例事件表

總結

今天稍微介紹了補間動畫的使用,並完成了飛鏢的飛行、旋轉動畫,還在投擲時加入的最小力道的判斷,飛鏢的部分總算是告一段落了,明天我們要來實作標靶的部分,這應該就比較簡單了,另外還有剛剛提到的,不讓顯示物件出現在舞台以外的地方的方法。


上一篇
[Day 22] 射飛鏢實作篇-浮動飛鏢、生成其他飛鏢
下一篇
[Day 24] 射飛鏢實作篇-設置舞台遮罩、設置標靶
系列文
什麼!在網頁上也可以寫遊戲?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言