設計以 XNA 為基礎的 遊戲

摘要

在上一篇文章中我們為大家介紹了 XNA Game Studio 4.0 的基本功能與支援遊戲設計的特性和優勢,做為使用 XNA Game Studio 4.0 版設計遊戲程式的基礎。這一回我們將要為大家介紹如何使用 Visual Studio 2010 或 Visual Studio 2010 Express for Windows Phone 設計以 XNA 為基礎的 Windows Phone 7 遊戲程式,並了解以 XNA 為基礎的遊戲程式的基礎架構與核心功能。

 XNA 遊戲程式結構

使用 Microsoft Visual Studio 2010 Express for Windows Phone 建立的 Windows Phone Game (4.0) 型態的專案中,名稱為 Game1.cs 的程式檔案是整個遊戲最主要的核心,負責定義名稱為 Game1 的類別,打造以 XNA 為基礎的遊戲的基本結構。有關使用 Microsoft Visual Studio 2010 Express for Windows Phone 建立 XNA 遊戲專案的說明可以參考:[Windows Phone 7 智慧型手機應用程式開發總覽]一文的說明。

Game1 類別繼承自 XNA Framework 提供的 Microsoft.Xna.Framework.Game 類別,預設會覆寫基礎類別的 Initialize 方法、LoadContent 方法、UnloadContent 方法、Update 方法、Draw 方法,加上 Game1 類別自己的建構函式,形成遊戲最基本的結構。例如以下就是一個 XNA 遊戲類別的最基本的類別及類別的結構:

public class Game1 : Microsoft.Xna.Framework.Game

{

    public Game1() {}

    protected override void Initialize() {}

    protected override void LoadContent() {}

    protected override void UnloadContent() {}

    protected override void Update(GameTime gameTime) {}

    protected override void Draw(GameTime gameTime) {}

}

 Game 類別主要方法的功能

在 Game1 類別覆寫基礎類別的方法中,名稱為 Initialize 的方法與 Game1 類別的建構函式負責執行遊戲初始化的工作,名稱為 LoadContent 的方法負責自 Content Pipeline 專案載入透過 Content Pipeline 技術預先處理成二進位資料的遊戲資源,名稱為 UnloadContent 的方法負責執行釋放資源的動作,請注意以 XNA 為基礎的應用程式只需要釋放非 ContentManager 管理的資源即可,意即未透過 ContentManager 類別的Add方法加入到 ContentManager 進行管理的資源才有需要在 UnloadContent 方法執行釋放資源的動作。

Game1 類別中名稱為 Update 的方法負責更新遊戲的狀態,例如要將遊戲的主角從 X 座標等於 100 的位置移動到 X 座標為 500 的位置,改變主角座標的動作就可以在 Update 方法中執行。請注意 Update 方法只負責更新遊戲的狀態,不負責更新遊戲的顯示畫面,換句話說,Update 方法只負責更新主角的座標位置,但是並不負責將主角顯示在新的座標位置,負責更新遊戲顯示內容的是名稱為 Draw 的方法,所有顯示遊戲最新狀態的工作,皆由 Draw 方法負責執行。

 XNA 遊戲程式的基本結構

了解 Game1 類別各個方法的基本功能之後,接下來我們就要來探討 Game1 類別各個方法必須執行的工作,以成功地建立一個能夠執行的 Windows Phone 7 遊戲程式。

圖1 所示即為一個 Windows Phone 7 遊戲程式從啟動到結束執行的運作過程,以及遊戲程式執行過程中每個階段必須執行的工作:

圖1:Windows Phone 7 遊戲程式從啟動到結束執行的各個階段必須執行的工作

[注意]

以 XNA 為基礎的 Windows Phone 7 遊戲程式在遊戲一開始會自動建立遊戲核心類別 (即 Game1 類別) 的物件,程式設計師不需要製作建立 Game1 類別的物件的程式碼。

遊戲程式開始執行並完成建立 Game1 類別的物件之後,第二個階段就是執行遊戲初始化。遊戲初始化階段主要的工作在建立 GraphicsDeviceManager 類別的物件。假設當做遊戲核心的類別的名稱為 Game1,則我們可以在 Game1 類別的建構函式中執行建立 GraphicsDeviceManager 類別的物件的動作,並設定 GraphicsDeviceManager 類別的物件的 PreferredBackBufferHeight 屬性和 PreferredBackBufferWidth 屬性,指定遊戲視窗的高度和寬度。除了設定 GraphicsDeviceManager 類別的物件的屬性以外,我們還可以設定 Game1 類別的物件的 TargetElapsedTime 屬性,控制遊戲程式更新狀態及顯示內容的頻率,做法如下:

XML
public Game1()
{
    graphics = new GraphicsDeviceManager(this);//建立 GraphicsDeviceManager 類別的物件
    Content.RootDirectory = "Content";					//設定遊戲資源的根目錄
    graphics.PreferredBackBufferHeight = 480;				//設定遊戲視窗的高度
    graphics.PreferredBackBufferWidth = 800;				//設定遊戲視窗的寬度
    // Frame rate is 30 fps by default for Windows Phone.
    TargetElapsedTime = 
TimeSpan.FromTicks(333333);//設定遊戲程式更新狀態及顯示內容的頻率為每秒 30 次
}
 

[說明]

Windows Phone 7 智慧型手機目前只有螢幕高度為 800,寬度為 480 的版本,因此將遊戲視窗設定成高度 480,寬度 800 的大小,表示遊戲要以橫式螢幕的方式執行,另外 Game1 類別的物件的 TargetElapsedTime 屬性負責控制遊戲程式更新狀態及顯示內容的頻率,將 TargetElapsedTime 屬性設定成 333333,表示更新頻率為 0.0333333,也就是每秒要更新 30 次。請注意每秒更新 30 次適合在 Windows Phone 7 智慧型手機平台執行的遊戲,但是不一定適合在 PC 個人電腦平台或 Xbox 360 遊機

遊戲程式完成初始化之後,第三個階段負責執行載入遊戲資源的動作,也就是要載入遊戲程式執行的時候需要用到所有資源,包括音效、音樂、圖形、和字型等等。負責載入遊戲程式需要使用的所有資源的動作可以交給 Game1 類別的 LoadContent 方法負責完成,例如以下就是負責載入遊戲程式需要使用的圖形資源的程式碼:

XML
Texture2D genie = null;								//宣告Texture2D類別的物件

protected override void LoadContent()
{
    // Create a new SpriteBatch, which can be used to draw textures.
    spriteBatch = new SpriteBatch(GraphicsDevice);		//建立 SpriteBatch 類別的物件

    // TODO: use this.Content to load your game content here
    genie = Content.Load<Texture2D>("genie");
}
 

請注意上述的程式碼會在遊戲程式初始化的階段建立 SpriteBatch 類別的物件,而建立 SpriteBatch 類別的物件的時候需要傳入 GraphicsDeviceManager 類別的物件當做參數。SpriteBatch 類別的物件主要的用途在顯示遊戲程式欲顯示的 2D 圖形,包括遊戲背景、遊戲人物、遊戲的狀態、甚至是遊戲提示供使用者選取的功能表。

除了建立 SpriteBatch 類別的物件以外,遊戲程式必須在初始化的階段負責載入遊戲程式執行時需要用到的所有資源,例如上述的程式碼中這一行程式碼:

XML
genie = Content.Load<Texture2D>("genie");
 

負責從 Content Pipeline 專案的根目錄載入名稱為 genie 的資源,因為程式碼指定欲載入的是 Texture2D 格式的資源,也就是圖形資源,所以在 Content Pipeline 專案中必須備妥名稱為 genie 的圖形檔案,其副檔名可以是 .bmp、.dds、.dib、.hdr、.jpg、.pfm、.png、.ppm、和 .tga 等常見的圖形格式檔案。有關 XNA 遊戲程式支援的圖形檔案格式可以參考 認識 XNA Game Studio 4.0 一文的說明。

[提示]

將上述程式碼中的 Texture2D 型態更換成 SoundEffect 型態,可以自 Content Pipeline 專案載入音效檔案 (副檔名為 .wma 的檔案),將上述程式碼中的 Texture2D 型態更換成 Song 型態,可以自 Content Pipeline 專案載入音樂檔案 (副檔名為 .mp3 的檔案),而將上述程式碼中的 Texture2D 型態更換成 SpriteFont 型態,可以自 Content Pipeline 專案載入字型定義檔案 (副檔名為 .SpriteFont 的檔案)。

[說明]

請注意上述的程式先在類別中宣告了一個型態為 Texture2D 類別,名稱為 genie 的變數,負責管理遊戲程式需要使用的圖形。

載入妥遊戲執行時需要用到的所有資源之後,遊戲程式就可以進入執行階段,處理使用者的輸入,更新遊戲的狀態,並顯示遊戲最新的內容。XNA 遊戲程式一進入執行階段便會不斷地呼叫 Update 方法和 Draw 方法,其詳細的行為與呼叫的頻率稍後會有詳細的討論。

假設遊戲程式利用 Game1 類別定義的 pos 變數控制遊戲人物顯示的位置,則程式設計師可以於 Game1 類別的 Update 方法中更新 pos 變數的內容值,以便改變遊戲人物顯示的位置,完成更新遊戲狀態的工作,如下:

XML
int pos = 0;										//存放遊戲人物位置的變數

protected override void Update(GameTime gameTime)
{
    // Allows the game to exit
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back ==
ButtonState.Pressed)	 //如果使用者按下智慧型手機的 [Back] 鍵,回到上一個畫面
        this.Exit();										//結束遊戲程式
if (pos <= 500)							//如果 pos 變數的內容值不大於 500
    {
        pos++;										//遞增 pos 變數的內容值
    }
    base.Update(gameTime);						//呼叫基礎類別的 Update 方法
}
 

請注意 Game1 類別的 Update 方法只負責更新遊戲的狀態,不負責更新遊戲顯示的內容,更新遊戲顯示內容的工作是由 Game1 類別的 Draw 方法負責的。例如以下的 Draw 方法便會將遊戲的人物移至 X 座標等於 pos 變數的內容值的位置:

XML
protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.CornflowerBlue);		//清除遊戲程式目前顯示的內容

    // TODO: Add your drawing code here
    spriteBatch.Begin();							//宣告顯示遊戲內容的動作開始
    spriteBatch.Draw(genie, new Vector2(pos,100),
Color.White);//將 genie 變數所管理的圖形的 x 座標顯示在 pos 變數的內容值指定的位置
    spriteBatch.End();							//宣告顯示遊戲內容的動作結束
    base.Draw(gameTime);								//呼叫基礎類別的 Draw 方法
}
 

[提示]

以 XNA 為基礎的遊戲程式可以在呼叫 spriteBatch 物件的 Begin 方法和呼叫 spriteBatch 物件的 End 方法之間執行多個繪製圖形和文字的動作,由 XNA Framework 以批次的方式一次顯示多個圖形內容。另外還有一點需要提醒大家的是 Game1 類別的 Update 方法和 Draw 方法都會接一個型態為 GameTime 的參數,程式設計師可以從這個參數得知遊戲程式開始迄今的時間,以及自上一次 Update 方法被呼到迄今的時間,做為控制更新遊戲狀態與更新遊戲內容的參考。

當遊戲程式結束執行的時候,遊戲程式可以利用 Game1 類別的 UnloadContent 方法釋放所有未透過呼叫 Content 物件的 Load 方法載入的資源。換句話說,所有透過呼叫 Content 物件的 Load 方法載入的資源可以不需要執行釋放的動作,呼叫 Content 物件的 Load 方法載入的資源會由 ContentManager 負責執行釋放的動作。

遊戲程式執行的最後一個階段是結束執行,結束遊戲程式執行的動作很簡單,遊戲程式只要呼叫 Game1 類別的 Exit 方法就可以結束遊戲程式的執行。

 Update 方法與 Draw 方法的呼叫時機

前面有提到,XNA 遊戲程式一進入執行階段便會不斷地呼叫 Update 方法和 Draw 方法,其中的 Update 方法負責更新遊戲程式的狀態,而 Draw 方法則負責顯示遊戲的內容。請注意並不是每一次 Update 方法被呼叫之後,Draw 方法就會跟著被呼叫,Update 方法與 Draw 方法被呼叫的頻率要視 Game1 類別的 IsFixedTimeStep 屬性的內容值而定。

如果 Game1 類別的 IsFixedTimeStep 屬性的內容值為 true (預設值),則遊戲程式處於固定更新 (fixed-step) 模式。使用固定更新模式的遊戲程式,其 Update 方法被呼叫的頻率是由 Game1 類別的 TargetElapsedTime 屬性的內容值定義的,其預設值視執行遊戲程式的平台的不同而有不同。如果遊戲程式在 PC 個人電腦或 Xbox 360 遊戲機中執行,Update 方法呼叫的頻率為每秒 60 次,如果遊戲程式在 Windows Phone 7 智慧型手機中執行,因為其處理器的速度較慢,Update 方法呼叫的頻率為每秒 30 次。

請注意 Update 方法被呼叫的頻率是一個遊戲程式努力要達到的目標值,而不是一定可以達到的數據。如果遊戲程式在 PC 個人電腦或 Xbox 360 遊戲機上執行,但是卻無法在 1/60 秒內完成 Update 方法和 Draw 方法執行的工作,則 Update 方法的 gameTime 參數 (型態為 GameTime 類別) 的 IsRunningSlowly 屬性將會被設定為 true,表示遊戲程式無法以正常的速度執行,此時遊戲程式會在呼叫 Update 方法之後,將不會伴隨著呼叫負責顯示遊戲內容的 Draw 方法,而是繼續呼叫 Update 方法,以跟上 TargetElapsedTime 屬性的內容值定義的更新頻率,如果此舉還是無法令遊戲程式跟上欲達到的更新頻率,則放棄。其結果將會造成遊戲程式在呼叫負責更新遊戲狀態的 Update 方法幾次之後才呼叫一次負責顯示內容的 Draw 方法,因此遊戲顯示的人物的動作將會呈現動作不順暢的現象。

當遊戲程式出現動作更新顯示不順暢的現象時,我們可以降低 TargetElapsedTime 屬性內容值,降低應用程式的更新頻率,或是將 Game1 類別的 IsFixedTimeStep 屬性的內容值為 false,令遊戲程式以可變更新 (variable-step) 模式來執行。請注意以可變更新模式執行的遊戲程式會不斷地呼叫 Update 方法和 Draw 方法,周而復始而且不間斷,不管 Game1 類別的 TargetElapsedTime 屬性的設定值為何。

[特別注意]

不管以 XNA 為基礎的遊戲程式採用固定更新 (fixed-step) 模式執行,或是採用可變更新 (variable-step) 模式執行,Game1 類別的 Update 方法和 Draw 方法都會持續地被呼叫,直到遊戲結束為止,也就是說遊戲程式本身都已經身處迴圈之中,除非有特殊的需求,否則在 Update 方法和 Draw 方法中不需要再使用迴圈的語法進行控制。例如我們要將遊戲中的動畫人物從X座標為 0 的位置移動到 X 座標為 500 的位置,不可以在 Game1 類別的 Update 方法加入以下的程式碼,以更新動畫人物的顯示位置 (假設 pos 是負責控制動畫人物 X 座標位置的變數):

XML
for (int i = 0; i <= 500; i++)
{
    pos = i;
}
 

因為上述的迴圈在執行的時候會造成 Update 方法執行較久,等 Update 方法執行完畢才會呼叫 Draw 方法,所以遊戲程式執行的時候我們將會看到動畫人物原本在X座標為 0 的位置,等迴圈跑完,動畫人物會直接在X座標為 500 的位置出現,使用者將不會看到動畫人物從X座標為 0 的位置移至 X 座標為 500 的位置的移動過程,造成動畫人物移動的過程很突兀,沒有漸進的效果。

要令動畫人物移動位置的時候有漸進的效果,我們可以在 Update 方法中利用以下的程式碼改變負責控制動畫人物 X 座標位置的 pos 變數的內容值:

XML
if (pos <= 500)
{
    pos++;
}
 

因為 Update 方法會被持續不斷地呼叫,每被呼叫一次,動畫人物的 X 座標的內容值就會改變,當 Draw 方法被呼叫的時候,使用者就可以看到動畫人物漸進移動至目標位置的效果。

[結語]

這一回我們為大家介紹了如何使用 Visual Studio 2010 或 Visual Studio 2010 Express for Windows Phone 設計以 XNA 為基礎的 Windows Phone 7 遊戲程式,並了解以 XNA 為基礎的遊戲程式的基礎架構與核心功能。下一回我們將要為大家介紹 XNA Framework 支援遊戲程式製作的重要類別,做為開發遊戲程式的基礎知識。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值