摘要
上一回我們為大家介紹了 XNA Framework 支援遊戲程式製作的重要類別,做為開發遊戲程式的基礎知識。除此之外,我們也利用所介紹的類別實作一個簡單的遊戲程式,並令其具有能夠不斷捲動的背景圖案。這一回我們將會介紹更多 XNA Framework 支援遊戲開發的類別,包括支援輸入控制,音效播放,以及背景音樂播放控制的類別等等,讓讀者能夠為所製作的遊戲程式加入更豐富的遊戲效果。
輸入控制
遊戲程式難免需要和使用者互動,讓使用者可以藉由輸入裝置,例如鍵盤、觸控面板、滑鼠、或是遊戲控制器進行遊戲控制,與遊戲程式達到互動的效果。要讓使用者控制遊戲程式的進行,可以利用 Keyboard 類別搭配 KeyboardState 結構,利用 TouchPanel 類別搭配 TouchCollection 結構,利用 Mouse 類別搭配 MouseState 結構,或是利用 GamePad 類別搭配 GamePadState 結構,對所操作的遊戲程式進行控制。
Keyboard 類別的功能很簡單,只提供名稱為 GetState 的方法以取得使用者操作鍵盤的按鍵狀態。遊戲程式可以呼叫 Keyboard 類別的 GetState 方法取得鍵盤的狀態 (型態為 KeyboardState 結構的傳回值),以判斷使用者按了那一個鍵。KeyboardState 結構的常用屬性請參考表1 的說明:
屬性名稱 | 說明 |
Item | 代表鍵盤的某個按鍵的按鍵狀態 |
KeyboardState 結構的常用方法請參考表2 的說明:
方法名稱 | 說明 |
GetPressedKeys | 取得目前所有被按下的按鍵 |
IsKeyDown | 判斷指定的按鍵是否已被按下 |
IsKeyUp | 判斷指定的按鍵是否已被放開 |
要判斷使用者操作滑鼠的做法和判斷使用者操作鍵盤的操作類別,遊戲程式可以先呼叫 Mouse 類別的 GetState 方法取得滑鼠的狀態 (型態為 MouseState 結構的傳回值),再透過滑鼠的狀態判斷使用者的操作動作。有關 Mouse 類別常用的方法可以參考表3 的說明:
方法名稱 | 說明 |
GetState | 取得包括滑鼠座標在內的滑鼠按鍵狀態 |
SetPosition | 設定滑鼠游標相對於遊戲視窗左上角的位置 |
MouseState 結構常用的屬性請參考表4 的說明:
方法名稱 | 說明 |
LeftButton | 滑鼠左鍵的按鍵狀態 |
MiddleButton | 滑鼠中間鍵的按鍵狀態 |
RightButton | 滑鼠右鍵的按鍵狀態 |
ScrollWheelValue | 記錄從遊戲開始執行迄今,滑鼠滾輪累計的捲動距離 |
X | 滑鼠游標的 X 座標位置 |
Y | 滑鼠游標的 Y 座標位置 |
雖然 Windows Phone 7 智慧型手機並未配備滑鼠,但是遊戲程式還是仍然能夠使用 Mouse 類別與 MouseState 結構判斷使用者操作滑鼠的動作,其效果相當於使用者對智慧型手機進行觸控操作。GamePad 類別和 GamePadState 結構也一樣,雖然 Windows Phone 7 智慧型手機未配備遊戲控制器,但是遊戲程式仍然能夠使用 GamePad 類別和 GamePadState 結構判斷使用者操作遊戲控制器的動作,當使用者按下 Windows Phone 7 智慧型手機下緣的硬體按鍵,其效果相當於透過遊戲控制器和遊戲程式溝通。例如在使用 Visual Studio 2010 Express for Windows Phone 建立的 Windows Phone Game (4.0) 的專案中,Game1 類別的 Update 方法便會利用以下的程式碼判斷使用者是否按下智慧型手機下緣回到上一個畫面的按鍵,如果是的話,則結束遊戲程式的執行:
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) //判斷使用者是否按下回到上一個畫面的按鍵 this.Exit(); //結束遊戲
GamePad 類別常用的方法可以參考表 5 的說明:
方法名稱 | 說明 |
GetCapabilities | 查詢遊戲控制器支援的功能的方法 |
GetState | 取得遊戲控制器的狀態 |
SetVibration | 設定遊戲控制器震動馬達的速度 |
GamePadState 結構常用的屬性可以參考表6 的說明:
屬性名稱 | 說明 |
Buttons | 取得遊戲控制器所有按鍵的狀態 |
DPad | 取得方向指引器指引的方向 |
IsConnected | 判斷遊戲控制器是否已連接到遊戲裝置 |
ThumbSticks | 取得遊戲控制器的搖捍的位置 |
Triggers | 取得遊戲控制器的觸控鈕的位置 |
GamePadState 結構常用的方法可以參考表7 的說明:
方法名稱 | 說明 |
IsButtonDown | 判斷指定的遊戲控制器按鈕是否被按下 |
IsButtonUp | 判斷指定的遊戲控制器按鈕是否已放開 |
Windows Phone 7 是一隻支援多點觸控智慧型手機,程式設計師可以利用 TouchPanel 類別搭配 TouchCollection 結構判斷使用者的觸控操作。TouchPanel 類別常用的屬性可以參考表8 的說明:
屬性名稱 | 說明 |
DisplayHeight | 代表觸控螢幕高度的屬性 |
DisplayOrientation | 代表觸控螢幕方向的屬性 |
DisplayWidth | 代表觸控螢幕寬度的屬性 |
EnabledGestures | 代表手勢操作是否啟用的屬性 |
IsGestureAvailable | 代表是否支援手勢操作的屬性 |
TouchPanel 類別常用的方法可以參考表9 的說明:
方法名稱 | 說明 |
GetCapabilities | 查詢觸控面板支援的功能的方法 |
GetState | 取得觸控面板目前的狀態的方法 |
ReadGesture | 讀取使用者手勢操作的相關資訊的方法 |
使用者對 Windows Phone 7 智慧型手機進行觸控及手勢操作的觸控資訊會存放在 TouchCollection 結構型態的變數中,程式設計師可以利用 TouchCollection 結構提供的屬性和方法取得使用者的觸控和手勢操作的相關資訊。TouchCollection 結構常的屬性可以參考表10 的說明:
屬性名稱 | 說明 |
Count | 取得觸控螢幕被使用者觸碰的位置的數目 |
IsConnected | 判斷觸控螢幕是否作用中 |
IsReadOnly | 判斷存放觸控螢幕被使用者觸碰的位置的集合是否唯讀 |
Item | 取得觸控螢幕被使用者觸碰的位置的相關資訊 |
TouchCollection 結構常的方法可以參考表11 的說明:
方法名稱 | 說明 |
Add | 新增一個觸碰點到存放觸碰位置的集合中 |
Clear | 清除存放觸碰點的集合的所有內容 |
Contains | 清除存放觸碰點的集合的所有內容 |
FindById | 依據 ID 搜尋觸碰點 |
IndexOf | 判斷指定的的觸碰點位於存放觸碰點的集合的編號 |
Insert | 插入觸碰點到存放觸碰點的集合的指定位置 |
Remove | 自存放觸碰點的集合移除指定的觸碰點 |
RemoveAt | 依據編號自存放觸碰點的集合移除指定的觸碰點 |
了解以 XNA 為基礎的遊戲的輸入控制技巧之後,接下來我們就要製作一個能夠允許使用者利用觸控的方式移動圖形的程式。
首先請啟動 Visual Studio 2010 Express for Windows Phone,建立一個 [Window Phone Game (4.0) 型態的專案],並於 Content Pipeline 專案加入一個圖形檔案 (例如內容為圓形的圖形檔案),做為使用者利用觸控面板移動的主體。做好之後請於 Game1 類別中宣告以下的變數,負責管理 2 維圖形,以及記錄 2 維圖形的位置:
Texture2D Ball; //管理 2 維圖形的變數 Vector2 BallPosition; //記錄 2 維圖形的位置
宣告好變數之後請修改 Game1 類別的建構函式,加入設定遊戲視窗大小的程式碼,編輯好的 Game1 類別建構函式如下:
public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; graphics.PreferredBackBufferHeight = 800; //設定遊戲視窗的高度為 800 graphics.PreferredBackBufferWidth = 480; //設定遊戲視窗的寛度為 480 // Frame rate is 30 fps by default for Windows Phone. TargetElapsedTime = TimeSpan.FromTicks(333333); }
設定好遊戲視窗的大小之後請修改 Game1 類別的 LoadContent 方法,負責載入 Content Pipeline 專案中事先準備好的圖形,並設定圖形要顯示在遊戲視窗的正中央:
protected override void LoadContent() { //Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); // TODO: use this.Content to load your game content here Ball = Content.Load<Texture2D>("Ball"); //載入名稱為 Ball 的圖形資源 BallPosition = new Vector2((Window.ClientBounds.Width - Ball.Width) (Window.ClientBounds.Height-Ball.Height)/2); //設定圖形顯示的位置在視窗正中央 }
[提示]
上述的程式碼利用 Game1 類別的 Window 屬性取得遊戲視窗,再利用遊戲視窗的 ClientBounds 屬性的 Width 成員和 Height 成員取得遊戲視窗的大小,做為計算圖形顯示位置的依據。
[注意]
讀者必須依據準備在 Content Pipeline 專案中的圖形資源名稱進行載入圖形資源的動作。
protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); // TODO: Add your update logic here TouchCollection tc=TouchPanel.GetState(); //取得使用者操作觸控面板的狀態 if (tc.Count > 0) //如果使用者有觸控螢幕的動作 { BallPosition = tc[0].Position; //將使用者第一個觸碰點當做顯示圖形的左上角點 } base.Update(gameTime); }
接下來請編輯 Game1 類別的 Draw 方法,將遊戲載入的圖形資源顯示在使用者觸碰的螢幕座標點,做好的 Draw 方法如下:
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here spriteBatch.Begin(); //開始繪製遊戲內容 spriteBatch.Draw(Ball, BallPosition, Color.White); //將載入的圖形資源顯示在 BallPosition 變數指定的座標位置 spriteBatch.End(); //結束繪製遊戲內容 base.Draw(gameTime); }
做好之後請按下 CTRL+F5 組合鍵執行遊戲程式,當遊戲程式開始執行的時候會將所載入的圖形顯示在遊戲視窗的正中央,當您觸碰 Windows Phone 7 智慧型手機的觸控螢幕的時候,遊戲程式顯示的圖形資源就會改變顯示位置到觸控螢幕被觸碰的座標點,如圖1 所示:
圖1:依據使用者觸碰觸控螢幕的座標點顯示圖形資源的遊戲程式執行的情形
音效與音樂
以 XNA 為基礎的遊戲程式可以利用 SoundEffect 類別或 SoundEffectInstance 類別播放音效,或是利用 Song 類別和 MediaPlayer 類別執行播放音樂的動作,讓遊戲程式可以播放悅耳的背景音樂。
在支援音效播放方面,SoundEffectInstance 類別提供更多的音效播放控制方法,而 SoundEffect 類別只能提供單純的音效播放功能。表12 所列為 SoundEffect 類別常用的屬性:
屬性名稱 | 說明 |
DistanceScale | 距離比例。當音源遠離使用者時,如果聲音衰減太快,則須遞增 DistanceScale 屬性的內容值,反之則須遞減 DistanceScale 屬性的內容值 |
DopplerScale | Doppler 比例。當音源接近使用者時,如果頻率升高太快,則須遞減 DopplerScale 屬性的內容值,反之則須遞增 DopplerScale 屬性的內容值 |
Duration | 控制音效播放時間長短的屬性 |
MasterVolume | 代表音量大小的屬性。內容值為 0.0f 代表不發出聲音 (靜音),內容值為 1.0f 代表最大音量 |
SpeedOfSound | 代表音速的屬性,內容值為每秒 343.5 公尺 |
表13 所列為 SoundEffect 類別常用的方法:
方法名稱 | 說明 |
CreateInstance | 能夠利用 SoundEffect 類別的物件建立 SoundEffectInstance 類別的物件的方法 |
FromStream | 能夠利用資料流建立 SoundEffect 類別的物件 |
Play | 負責播放音效的方法 |
SoundEffect 類別支援控制音效播放的功能較少,例如只支援播放音效的 Play 方法而未支援停止音效播放 Stop 方法,而且也未提供重覆播放音效的功能,如果遊戲程式需要對所播放的音效執行進階控制,就可以利用 SoundEffect 類別提供的 CreateInstance 方法建立 SoundEffectInstance 類別的物件,以便對所播放的音效執行更進階的控制。
表14 所示即為 SoundEffectInstance 類別常用的屬性:
屬性名稱 | 說明 |
IsLooped | 控制音效是否需要重覆播放的屬性 |
Pan | 控制音效平移的屬性 |
Pitch | 控制音效的音調高低的屬性 |
State | 代表音效播放狀態的屬性。其內容值為 Paused、Playing、Stopped 三種狀態之一 |
Volume | 控制音效播放音量的屬性 |
有關 SoundEffectInstance 類別常用的方法可以參考表15 的說明:
方法名稱 | 說明 |
Apply3D | 播放 3D 音效 |
Pause | 暫停音效播放 |
Play | 播放音效 |
Resume | 恢復音效播放 |
Stop | 停止音效播放 |
如果遊戲程式欲播放的是音樂,例如副檔名為 mp3 的音樂或歌曲當做遊戲的背景音樂,就必須用到 Song 類別和 MediaPlayer 類別。Song 類別負責管理遊戲程式欲播放的音樂或歌曲,其常用的屬性請參考表16 的說明:
屬性名稱 | 說明 |
Duration | 代表歌曲長度的屬性 |
IsProtected | 代表音樂是否為數位版權管理 (DRM) 的內容 |
Song 類別常用的方法可以參考表17 的說明:
方法名稱 | 說明 |
FromUri | 利用 Uri 指向的音樂建立 Song 類別的物件 |
建立好負責管理音樂或歌曲的 Song 類別的物件之後,就可以利用 MediaPlayer 類別進行播放與控制。MediaPlayer 類別常用的屬性可以參考表18 的說明:
屬性名稱 | 說明 |
IsMuted | 控制是否要調整成靜音模式的屬性 |
IsRepeating | 控制是否要重覆播放音樂的屬性 |
PlayPosition | 取得目前播放位置的屬性 |
State | 代表目前播放狀態的屬性。其內容值為 Paused、Playing、Stopped 三種狀態之一 |
Volume | 控制播放音量的屬性 |
MediaPlayer 類別常用的方法可以參考表19 的說明:
方法名稱 | 說明 |
Pause | 暫停音樂播放 |
Play | 播放音樂 |
Resume | 恢復音樂播放 |
Stop | 停止音樂播放 |
為遊戲程式加入音效和背景音樂
了解以 XNA 為基礎的遊戲程式支援播放音效與音樂的基本功能之後,接下來我們就要為所開發的遊戲程式加入背景音樂。
首先請為 [Windows Phone Game (4.0)] 專案中的 Content Pipeline 專案加入當做背景音樂與音效的資源檔案,例如您可以為專案加入副檔名為 .wma 的檔案當做遊戲程式的音效資源,為專案加入副檔名為 .mp3 或 .wma 的檔案當做遊戲的背景音樂。有關 Content Pipeline 專案支援的音效與音樂資源格式可以參考 [認識 XNA Game Studio 4.0] 一文的說明。
加入妥音效資源和背景音樂資源之後,請於 Game1 類別加入以下的變數宣告,負責管理音效資源,播放音效的 SoundEffectInstance 類別的物件,以及管理背景音樂的 Song 類別的物件:
SoundEffect HitWall; //管理球體碰撞到遊戲視窗邊界的音效的變數 SoundEffectInstance HitWallEffect; //控制音效播放的變數 Song BackgroundSong; //管理遊戲背景音效的變數
接下來請編輯 Game1 類別的 LoadContent 方法,加入以下的程式碼,執行載入音效和音樂資源的動作:
HitWall = Content.Load<SoundEffect>("HitWall"); //載入名稱為 HitWall 的音效資源 HitWallEffect = HitWall.CreateInstance(); //建立播放音效資源的 SoundEffectInstance 物件 HitWallEffect.Apply3D(new AudioListener(), new AudioEmitter()); //呼叫 SoundEffectInstance 物件的 Apply3D 方法,播放 3D 音效 BackgroundSong = Content.Load<Song>("SuperMario");//載入名稱為 SuperMario 的背景音樂資源 MediaPlayer.IsRepeating = true; //將MediaPlayer類別的IsRepeating屬性設定成true,表示要不中斷地重覆播放背景音樂 MediaPlayer.Play( BackgroundSong); //呼叫 MediaPlayer 類別的 Play 方法播放名稱為 //BackgroundSong的物件管理的背景音樂
最後請編輯 Game1 類別的 Update 方法,加入以下的程式碼,以便在使用者利用觸碰觸控螢幕移動遊戲程式顯示的圖形時,判斷所移動的圖形是否碰撞到遊戲視窗的邊界,以決定是否要播放碰撞的音效:
if (BallPosition.X == 0 || BallPosition.X > Window.ClientBounds.Width - Ball.Width || BallPosition.Y==0 || BallPosition.Y > Window.ClientBounds.Height-Ball.Height) //判斷圖形是否碰撞到遊戲視窗的四個邊界 { HitWallEffect.Play(); //播放碰撞的音效 }
[說明]
控制播放音效與背景音樂的動作屬於控制遊戲程式狀態的範疇,和顯示遊戲程式內容無關,所以不需要修改 Game1 類別的 Draw 方法。
做好之後請按下 CTRL+F5 組合鍵執行專案,待遊戲程式啟動之後,讀者就可以聽到不斷重覆播放的背景音樂。當您觸碰遊戲程式的視窗以移動戲程顯示的圖形時,只要圖形碰觸到遊戲視窗的邊界,就會聽到遊戲程式發出的碰撞音效。
範例下載:TouchMoveBall.zip
[結語]
這一回我們為大家介紹了更多的 XNA Framework 支援遊戲開發的類別,包括支援輸入控制,音效播放,以及背景音樂播放控制的類別等等,讓讀者能夠為所製作的遊戲程式加入更豐富的遊戲效果。下一回我們將要為大家介紹進階的輸入控制,例如手勢觸控輸入,進階音效控制技巧,碰撞偵測,以及輔助 XNA 遊戲設計的好用類別。