游戲中的背景音樂和聲效
不管是大型客戶端游戲還是輕量級的網頁游戲,游戲中背景音樂和聲效是必不可少的。好的背景音樂、聲效會給游戲增色,本文不從策划/設計等角度去考慮,只從程序實現上面講在網頁游戲開發中如何去實現背景音樂、聲效。背景音樂和聲效有以下幾個要求:
ü 背景音樂與聲效是分開的,可以獨立設置開關
ü 背景音樂一般循環播放一直存在
ü 聲效點擊才觸發,這種聲音任何時候只播放一個,如果兩個瞬間點擊多個按鈕,只播放最后一個聲音
為了使背景音樂和聲效分開,可以使用不同的聲道來播放,這樣可以通過控制聲道以控制背景音樂和聲效。而任何時刻只播放一個聲效,可以有多種方法,如:
①通過一個單例類來控制管理所有的聲效,保證每次只播放一個聲效;
②將所有的聲效放嵌入到一個swf中,並將所有聲效放到一個時間軸上,播放的時候跳到相應幀,這樣可以保證每次只播放一個聲效。
本文主要介紹第二總方法,使用單例模式來管理游戲中的背景音樂和聲效,大綱如下:
1. AS3中聲音控制相關類
在 ActionScript 中控制聲音之前,需要先將聲音信息加載到 Flash Player 中。可以使用四種方法將音頻數據加載到 Flash Player 中,以便通過 ActionScript 對其進行使用:
ü 將外部聲音文件(如 mp3 文件)加載到 SWF 中(方法一是本文要用的,背景音樂及游戲中的按鈕聲效都是單獨的mp3文件,然后加載到游戲中);
ü 在創建 SWF 文件時將聲音信息直接嵌入到其中(前面我們講到的,創建 SWF 文件時將聲音信息直接嵌入到其中,我們可以將所有的聲效放嵌入到一個swf中,並將所有聲效放到一個時間軸上,播放的時候跳到相應幀,這樣可以保證每次只播放一個聲效。);
ü 使用連接到用戶計算機上的麥克風來獲取音頻輸入;
ü 訪問從服務器流式傳輸的聲音數據。
從外部聲音文件加載聲音數據時,可以在仍加載其余聲音數據的同時開始回放聲音文件的開頭部分。 雖然可以使用各種不同的聲音文件格式對數字音頻進行編碼,但是 ActionScript 3.0 和 Flash Player 支持以 mp3 格式存儲的聲音文件。它們不能直接加載或播放其它格式的聲音文件,如 WAV 或 AIFF。
在 ActionScript 中處理聲音時,可能會使用 flash.media 包中的某些類。通過使用 Sound 類,您可以加載聲音文件並開始回放以獲取對音頻信息的訪問。開始播放聲音后,Flash Player 可為您提供對 SoundChannel 對象的訪問。由於已加載的音頻文件只能是在用戶計算機上播放的幾種聲音之一,因此,所播放的每種單獨的聲音使用其自己的 SoundChannel 對象;混合在一起的所有 SoundChannel 對象的組合輸出是實際通過計算機揚聲器播放的聲音。可以使用此 SoundChannel 實例來控制聲音的屬性以及將其停止回放。最后,如果要控制組合音頻,可以通過 SoundMixer 類對混合輸出進行控制。
ActionScript 3.0 聲音體系結構使用 flash.media 包中的以下類。
類 |
描述 |
flash.media.Sound |
Sound 類處理聲音加載、管理基本聲音屬性以及啟動聲音播放。 |
flash.media.SoundChannel |
當應用程序播放 Sound 對象時,將創建一個新的 SoundChannel 對象來控制回放。SoundChannel 對象控制聲音的左和右回放聲道的音量。播放的每種聲音具有其自己的 SoundChannel 對象。 |
flash.media.SoundLoaderContext |
SoundLoaderContext 類指定在加載聲音時使用的緩沖秒數,以及 Flash Player 在加載文件時是否從服務器中查找跨域策略文件。SoundLoaderContext 對象用作 Sound.load() 方法的參數。 |
flash.media.SoundMixer |
SoundMixer 類控制與應用程序中的所有聲音有關的回放和安全屬性。實際上,可通過一個通用 SoundMixer 對象將多個聲道混合在一起,因此,該 SoundMixer 對象中的屬性值將影響當前播放的所有 SoundChannel 對象。 |
flash.media.SoundTransform |
SoundTransform 類包含控制音量和聲相的值。可以將 SoundTransform 對象應用於單個 SoundChannel 對象、全局 SoundMixer 對象或 Microphone 對象等。 |
flash.media.ID3Info |
ID3Info 對象包含一些屬性,它們表示通常存儲在 mp3 聲音文件中的 ID3 元數據信息。 |
flash.media.Microphone |
Microphone 類表示連接到用戶計算機上的麥克風或其它聲音輸入設備。可以將來自麥克風的音頻輸入傳送到本地揚聲器或發送到遠程服務器。Microphone 對象控制其自己的聲音流的增益、采樣率以及其它特性。 |
加載和播放的每種聲音需要其自己的 Sound 類和 SoundChannel 類的實例。然后,全局 SoundMixer 類在回放期間將來自多個 SoundChannel 實例的輸出混合在一起。另外,Sound、SoundChannel 和 SoundMixer 類不能用於從麥克風或流媒體服務器(如 Flash Media Server)中獲取的聲音數據。
2. as3中單例模式如何設計
單例模式(Singleton)單例模式(也叫單件模式)的作用就是保證在整個應用程序的生命周期中,任何一個時刻,單例類的實例都只存在一個。一般編程語言中,單例模式有以下兩個特點:
ü 單例模式使類在程序生命周期的任何時刻都只有一個實例
ü 單例的構造函數是私有的,這樣可以阻止調用構造函數生成實例,必須通過getInstance()接口得到這個單例類的實例
然而由於AS3中的構造函數必須是public,所以不可以像其它編程語言一樣,將構造函數置為private來阻止調用構造函數生成實例。這樣是不是說as3天生就不支持單例模式了呢?很多人這樣來實現單例模式:
protected static var instance : Singleton; public function Singleton() { if (instance != null) { //throw new Error("只能用getInstance()來獲取實例"); } } public static function getInstance() : Singleton { if (instance == null) { instance = new Singleton(); } return instance; }
想阻止構造函數在類的外部被調用還有另外一種方法,使用as3中的包外類。包外類:只能被包中的類訪問,它屬於當前類的私有類。此包外類對外不可見。定義位置為package{ }外。可以定義一個或者多個class類。但類名不能與文件同名。具體如何使用包外類實現單例模式,見下面小節。
注意:flash是單線程模式的,不用考慮線程安全問題。
有了上面的基礎,下面可以游戲中的聲音管理類了,聲音管理類設計成一個單例類。通過兩個聲道SoundChannel分別播放背景音樂、聲效;SoundLoaderContext類設置MP3文件加載上下文;Sound 類處理聲音加載、管理基本聲音屬性以及啟動聲音播放。完整的代碼如下:
package utils { import flash.events.EventDispatcher; import flash.media.Sound; import flash.media.SoundChannel; import flash.media.SoundLoaderContext; import utils.QAssetManager; /** * 游戲中背景音樂、聲效管理類: * 聲音的播放,即將Sound.play()方法賦值給SoundChannel實例就可以開始播放歌曲了。 * 如果使用Sound和SoundChannel裝載和播放另一個mp3時,這個聲音也會開始播放,因為沒有對實例做任何限制,因此兩個實例都可以正常播放。 * 因此必須檢測是否對SoundChannel實例賦值了,如果它是null,腳本繼續執行並播放選擇的文件;如果它不是null,先停止當前正在播放的文件 * 后再裝載和播放另一個mp3文件。這樣就可以保證某一時刻只播放一個文件了。 * * 游戲中聲音有2兩種: * 1. 背景音樂:循環播放一直存在 * 2. 按鈕音效等:點擊才觸發,這種聲音任何時候只播放一個,如果兩個瞬間點擊多個按鈕,只播放最后一個聲音 * @author tyler */ public class GameSound extends EventDispatcher { //public static const SOUND_BACKGROUND:int = 0; protected var m_bkmusicChannel:SoundChannel; protected var m_soundChannel:SoundChannel; //單態實例 protected static var m_instance:GameSound; //單態構造函數 public function GameSound(pvt:PrivateClass) { } //單態構造方法 public static function getInstance():GameSound { if (m_instance == null) { m_instance = new GameSound(new PrivateClass()); } return m_instance; } //開始播放背景音樂 public function bkmusicPlay(music:String):void { bkmusicStop(); QAssetManager.getInstance().getAssets( music, {context: new SoundLoaderContext() }, function(content:Object):void { m_bkmusicChannel = (content as Sound).play(); }); } //停止播放背景音樂 public function bkmusicStop():void { if (m_bkmusicChannel != null) { m_bkmusicChannel.stop(); } } //播放音效 public function soundPlay(sound:String):void { soundStop(); QAssetManager.getInstance().getAssets( sound, {context: new SoundLoaderContext() }, function(context:Object):void { m_soundChannel = (context as Sound).play(); }); } //停止音效 public function soundStop():void { if (m_soundChannel != null) { m_soundChannel.stop(); } } } } class PrivateClass { public function PrivateClass() { trace("包外類,用於實現單例"); } }
播放背景音樂的時候只需要這樣調用:GameSound.getInstance().bkmusicPlay(url);播放其它聲效時:GameSound.getInstance().soundPlay(url)。停止的話調用相應接口即可。
注意:utils.QAssetManager只是一個加載的通用類,大家可以使用自己的加載類,我推薦開源的BulkLoader。
你可能感興趣的還有: