前陣子,我們介紹了許多跟畫面顯示有關的功能,而今天,我們要來介紹遊戲中除了畫面以外,另外一個同等重要的元素——聲音。
PixiJS 雖然作為一個 2D 繪圖引擎,但它其實還提供了一系列與音訊有關的功能,讓我們可以快速的播放、控制音訊。如果你是在自己的環境的話,需要先自行安裝 pixijs/sound 這個擴充套件,因為它並不包含在 PixiJS 本體裡面。不過 CG 作為一個線上遊戲開發平台,自然也是幫我們把這一步做好了,而我們要做的事情就是享用它!
與創建 Sprite 一樣,我們需要先載入音訊檔案至專案中,再利用資源的別名來播放音訊,詳細的載入方式可以參考 Day 03,你可以使用其他人上傳的公開音訊,也可以自行上傳音訊,.mp3
、.ogg
等皆可。
確保專案內已經有音訊資源後,就可以用下方程式碼的方式來播放音訊。
import pixi = CG.Pixi.pixi;
async function start() {
// 載入資源(記得將資源別名修改成你自己專案的資源別名喔!)
await pixi.assets.add("ironman2025_cook.音效.pop").load();
// 播放音效
pixi.assets.playSound("ironman2025_cook.音效.pop");
}
start();
所有的專案資源在使用前,都必須利用 pixi.assets
將該資源載入至遊戲中。
而在 CG 上,pixi.assets
幫我們把播放音訊這件事情變得更加簡單了,只需要一行程式碼 pixi.assets.playSound()
,我們就可以播放音訊。
而如果你想要改變播放的音訊音量,或是讓它循環播放,可以這樣:
pixi.assets.playSound("ironman2025_cook.音效.pop", {
volume: 0.5, // 音量 50%
loop: true // 啟用循環播放
});
如此一來,這個音效的音量就會被調整到 50%,並且循環播放。volume
的範圍通常是 0 ~ 1,0 就是 0%,1 就是 100% 的意思。
PIXI.sound.Sound
雖然 playSound()
提供了便利的播放功能,但在某些情境下,你可能會需要更直接地操作音訊物件本身,例如:暫停、恢復或停止播放。這時,我們就需要使用 pixi.assets.getSound()
來取得 PIXI.sound.Sound
物件。
// 取得 sound 物件
const sound: PIXI.sound.Sound = pixi.assets.getSound("ironman2025_cook.音效.pop");
// 播放音訊
sound.play({ volume: 0.5, loop: true });
PIXI.sound.Sound
物件讓我們可以對聲音進行控制。以下是一些常用的方法:
sound.play()
:播放音訊。sound.pause()
:暫停播放。sound.resume()
:從暫停的地方繼續播放。sound.stop()
:停止播放,並將播放進度歸零。有了這些方法,你就可以輕鬆實現背景音樂的暫停與恢復功能,這在遊戲暫停選單中非常有用。
直接對 Sound
操作的話,會影響到所有由這個 Sound
創建的 IMediaInstance
,例如停止所有 IMediaInstance
的播放,下面再來看看 IMediaInstance
是什麼。
PIXI.sound.IMediaInstance
如果你想要更細緻地操控音訊,例如同時播放多個相同的音效,並分別控制它們的音量,就需要處理單一播放實例(Instance)。一個 Sound
物件可以有多個播放實例,每個實例都代表著一次獨立的音訊播放。
pixi.assets.playSound()
播放 Sound
的回傳值就是一個 PIXI.sound.IMediaInstance
物件。
const instance: PIXI.sound.IMediaInstance = pixi.assets.playSound("ironman2025_cook.音效.pop");
這個 instance
物件讓我們能對這次播放進行獨立的控制,而不會影響到其他正在播放的相同音效。
// 暫停這個特定的音效播放實例
instance.pause();
// 播放這個特定的音效播放實例
instance.resume();
// 停止這個特定的音效播放實例
instance.stop();
// 檢查這個實例是否正在播放
console.log(instance.isPlaying); // true 或 false
// 隨時調整這個實例的音量
instance.volume = 0.8;
這個功能在處理快速重複的音效時非常有用,例如射擊遊戲中的槍聲,每次射擊都會產生一個新的播放實例,讓你可以獨立地控制每一發子彈的聲音。
此外,你還可以利用這個特性來避免聲音重疊。舉例來說,當玩家連續快速射擊時,你可能不希望有太多個槍聲同時響起而造成雜音。這時,你就可以在每次播放新音效前,先停止上一個播放實例,或是將其音量快速淡出,如此一來,就能有效管理音訊,讓遊戲體驗更流暢。
還記得 Day 11 的 Tween 嗎?它不只是可以用在 PixiJS 上製作動畫,前面我們提到了如何使用 IMediaInstance
物件來控制單一音效的播放,這時,如果我們再結合昨天介紹的 Tween,就可以實現一些很酷的效果,例如音效淡入淡出`。
這個功能在遊戲中非常實用,像是當玩家進入一個新場景時,你可以讓背景音樂從無聲慢慢淡入;或是當遊戲暫停時,讓背景音樂慢慢淡出。
// 播放音樂,將一開始的音量設定為 0,並將音效實例儲存在 musicInstance
const musicInstance = pixi.assets.playSound("ironman2025_cook.音樂.bgm", { volume: 0 });
// 創建一個 Tween,將 instance 的音量從 0 淡入到 0.5
new TWEEN.Tween(musicInstance)
.to({ volume: 0.5 }, 2000) // 2000 毫秒內將音量從 0 漸變到 0.5
.start();
怎麼樣?想不到 Tween 還可以這樣用吧!同樣的,我們也可以搭配緩動函數(Easing Function)來讓音訊的淡入淡出變得更加平滑順暢,這個部分就給各位去琢磨琢磨啦~
今天的內容讓我們將「聲音」這個重要元素帶進了遊戲。
pixi.assets.playSound()
來播放音效。pixi.assets.getSound()
取得 PIXI.sound.Sound
物件來操作。PIXI.sound.IMediaInstance
來進行最細緻的控制。經過這幾天的介紹,我們已經掌握了遊戲主迴圈(Game Loop)、補間動畫(Tween)、**圖集動畫(Spritesheet)和音訊控制(Sound)**這四大核心技術。
明天,我們將把所有學到的知識融會貫通,將第一階段做個總結,一起動手實作一個會動、會響、且能夠互動的小場景吧!