iT邦幫忙

2025 iThome 鐵人賽

DAY 11
1

Day 04 的時候,我們曾介紹過如何讓 Sprite 移動,並利用循環更新使其產生動畫效果,但一天所展示的都是持續性動畫,就是會一直做,直到我說停,或是不知道何時會停下來的動畫。而今天我們要來介紹如何用更簡單的方式,讓顯示物件實現一次性的動畫。

PixiJS 本身並沒有內建可以讓我們快速實現一次性動畫的功能,因為它是一個 2D 繪圖引擎,只專注於畫面渲染,不過在 CG 上,載入 Pixi 模組的同時,就會順便載入一個能讓我們輕鬆實現一次性動畫的函示庫——Tween.js

▸ Tween.js

Tween.js 也是一個輕量級的 JavaScritp 函示庫,用於實現讓物件屬性的值,以一個指定的時間,從 x 過渡到 y 的效果。

以下,讓我們直接以實際的例子來看看 Tween 是怎麼運作的:

// 創建一個 Tween 補間動畫物件,設定物件、屬性、動畫時間後,開始執行動畫。
new TWEEN.Tween(witch)
    .to({ x: witch.x + 200 }, 1000)
    .start();

這段程式碼以最簡潔的方式執行了補間動畫,其中包含了三個核心步驟:

  • new TWEEN.Tween(witch):首先,我們創建一個新的 Tween 物件,並將要被動畫化的目標物件傳入。(witch 就是前幾天一直出現的女巫 Sprite)
  • .to({ x: witch.x + 200 }, 1000):這部分定義了動畫的「終點」和「時間」。{ x: witch.x + 200 } 指定了目標屬性,告訴程式我們想讓 witchx 座標移動到當前位置右邊 200 像素。而 1000 則代表整個動畫將使用 1000 毫秒來完成。
  • .start():最後,呼叫 .start() 來啟動這個動畫。

Tween 基本使用 預覽

▸ 緩動函數(Easing Functions)

在上面的程式碼中,動畫的移動是等速的,但遊戲中的動畫通常需要更豐富的動態效果,例如彈出視窗的放大會一開始快,甚至超過目標大小,最後慢慢縮回至目標大小。這時,我們就需要使用緩動函數(Easing Functions)

Tween.js 提供了豐富的緩動函數,我們可以透過 .easing() 方法來指定。

new TWEEN.Tween(witch)
    .to({ x: witch.x + 200 }, 1000)
    .easing(TWEEN.Easing.Bounce.Out) // 使用彈跳效果的緩動函數
    .start();

這個範例會讓女巫精靈以一種彈跳的方式,平滑地移動到目標位置。

Tween BounceOut 預覽

  • TWEEN.Easing.Linear.None:等速移動,最簡單的緩動效果。(預設使用)
  • TWEEN.Easing.Cubic.Out:先快後慢,物件會快速移動到終點附近,然後逐漸減速停止。
  • TWEEN.Easing.Back.Out:回彈效果,物件會先稍微超出目標,然後再彈回。
  • TWEEN.Easing.Elastic.Out:彈簧效果,物件會像彈簧一樣震盪數次後停下。
  • TWEEN.Easing.Bounce.Out:彈跳效果,就像一個球落地後彈跳數次。

你可以在 Tween.js 官方範例 中看到所有緩動函數的視覺化效果,這能夠幫助我們更直觀地選擇適合的動畫風格。

▸ 事件回呼(Event Callbacks)

Tween.js 也提供了許多事件,讓開發者可以在動畫的不同階段執行自訂的函數。其中我個人最常用的是 onComplete(),它會在動畫結束時被觸發。

new TWEEN.Tween(witch)
    .to({ x: witch.x + 500 }, 1500)
    .easing(TWEEN.Easing.Cubic.Out)
    .onComplete(() => {
        // 動畫結束時讓女巫翻轉
        witch.scale.x *= -1;
    });

Tween onComplete 預覽

▸ 串接多個動畫(Chaining)

當你需要讓多個動畫依序執行時,可以使用 .chain() 函數,這讓動畫的流程控制變得非常簡單。

// 第一個動畫:向右移動,到達終點後左右翻轉
const tween1 = new TWEEN.Tween(witch)
    .to({ x: witch.x + 500 }, 1500)
    .easing(TWEEN.Easing.Cubic.Out)
    .onComplete(() => {
        witch.scale.x *= -1;
    });

// 第二個動畫:向左移動,到達終點後左右翻轉
const tween2 = new TWEEN.Tween(witch)
    .to({ x: witch.x }, 1500)
    .easing(TWEEN.Easing.Cubic.Out)
    .onComplete(() => {
        witch.scale.x *= -1;
    });

// 將 tween1 的結束與 tween2 的啟動串聯起來
tween1.chain(tween2);

// 啟動第一個動畫
tween1.start();

Tween chain 預覽

點我查看範例程式碼

▸ 循環更新 vs. Tween:該如何選擇?

你可能會好奇,既然循環更新和 Tween 都能讓物件動起來,那什麼時候該使用哪一個呢?

這個問題的答案很簡單:

  • 循環更新:適合處理持續性需要精準控制的遊戲邏輯。例如,玩家角色根據鍵盤輸入移動、物理模擬、或是每幀更新計時器。這些動作需要我們逐幀去計算和更新狀態。
  • Tween:適合處理一次性結果導向的平滑動畫。例如,UI 視窗彈出、按鈕點擊後縮放、物件淡入淡出、或是敵人死亡後的飛離效果。你只需要設定「從哪裡」到「哪裡」,動畫就會自動完成。

▸ 總結

今天我們介紹了如何使用 Tween.js 來實現物件的平滑移動。Tween 讓複雜的動畫變得非常容易,你可以透過 .to() 來指定終點,並使用 .easing() 來控制動畫的節奏。並且 Tween 不只是可以使用在 PixiJS 上而已,任何需要讓某個數值平滑的改變到目標值的時候,都可以使用到。

除了這種在一定時間內移動、縮放顯示物件的動畫效果,明天,我們會來介紹另外一種截然不同的動畫技術,遊戲世界中的定格動畫——Spritesheet


上一篇
Day 10:遊戲的生命週期 - 更新循環系統
下一篇
Day 12:遊戲世界中的定格動畫 - Spritesheet
系列文
用 PixiJS 寫遊戲!告別繁瑣設定,在 Code.Gamelet 打造你的第一個遊戲12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言