本文章是由機器翻譯。

要放置

在方 Zune: 金鑰進行遊戲

Mike Calligaro

內容

男人,C That Is 清晰
在遊戲的剖析
Pixie 灰塵的小精靈
資產名稱的色彩鍵
你得移動到播放
精靈在方塊中
Bing 就 Boom
進階繪圖
其餘部分就是您 Up To

使用者的已玩 Xbox,因為他是三個,我兒子已開始顯示的程式設計的興趣,特別撰寫的遊戲。 這個提示我下載 XNA 遊戲 Studio 中,並探討它自己,您知道,讓我可以教他。 我已經永遠要撰寫自己的遊戲,必須與它。 真的。

XNA 遊戲 Studio 3.0 加入了能夠撰寫這表示,Zune 現在是行動開發平台的 Zune 的遊戲。 因此相當,呃,遊戲要放置的文件中。 如果您已經為 XNA 開發人員,我可能會檢閱您已瞭解一些概念。 但是,如果您像我一樣,人員 enthusiastic 有關,但遊戲開發,相當的新讀取上。

男人,C That Is 清晰

大部份我在 Microsoft 的 15 年工作我已經在系統及驅動程式開發人員。 我選擇的必要性的語言已在相當 bare 骨頭 C ++。 我很少會使用 MFC 和 Microsoft.NET Framework 執行階段。 直到最近,我無法有甚至拼字 STL 較不使用它。

這是我每天的工作。 但是在我的關閉時間我喜歡周圍使用 C# 的播放。 通常我會撰寫小應用程式,我的 Windows Mobile 裝置和有時候我的電腦。 C ++ 並不視為我一樣許多原生開發人員,但我仍得到一些 giddy 當我在 C# 所撰寫時,錯誤。 您可以取得大量使用極少行程式碼。 我發誓那 C# 是因此更有趣他們應該進行它在 controlled 功能。

在 [有趣] 類別 XNA 遊戲 Studio 就像 C# steroids 上。 有權小組已完成的驚人的工作,讓遊戲開發簡單。 .Framework 簡單,大部分處理硬碟的東西,它們已發行的目標在於教導您遊戲的開發,各種不同層面的範例資料堆。

開始 Creators.xna.com。 從那裡您可以下載免費的 XNA 遊戲 Studio 3.0。 如果您已經使用其中一個,Visual Studio 2008 的各種擔任,XNA 遊戲 Studio 將會與它整合。 如果您沒有 Visual Studio 2008,煩惱。 XNA 遊戲 Studio 也可以搭配可用 Visual C# Express Edition。 (也就是說我提到 Visual Studio 時,雖然您可以用 Visual C# Express Edition 如果您正在使用)。

Creators.xna.com 網站也是資訊的可協助您進行的。 按一下頂端頁面以尋找初學者指南,範例,教育 」 連結,以及如何-到的。 《 初學者的手冊以 2D 遊戲 》 為特別好,為文件,與 XNA 遊戲 Studio 一起安裝。 在某些的情況下安裝說明文件會有那不是 Web 上的資訊。 在 Visual Studio,您可以取得該文件,選取 [說明] | 內容] 並 [將設定 [XNA 為的 [篩選器遊戲 Studio 3.0。

XNA 遊戲 Studio 可讓您撰寫一個程式碼基底,和將它部署到 Xbox、 PC 和 Zune。 所有我在此將運作在所有三個平台上。 免費的下載您需要開發 PC 或 Zune,但 Xbox 開發需要高階成員資格的成本年度付費。

在遊戲的剖析

一旦你 XNA 遊戲 Studio 3.0 安裝,就可以建立為 Hello World Zune 的遊戲藉由選取 [檔案 | 新增 | 專案。 然後選取 [Visual C# | XNA 遊戲 Studio 3.0,並按一下 [Zune 遊戲 (3.0)。 雖然這會產生的程式實際上未指明 Hello World,監看的輸入、 繪製背景的藍色,並視結束。

如果您必須有真正複雜,您在愉快的意外的。 程式碼的大約 20 行您整個遊戲的基礎結構大量會散佈超過六個函式。 以下是這些函式的描述。

建構函式是只在標準,處理序區各種 C# 物件建構函式。 視為它相同就像其他任何一個。

之後您建構函式完成,會呼叫初始化)。 它可讓您進行進一步的特別針對項目有關的圖形系統初始設定。

LoadContent 會稱為初始化之後,而且會載入您的影像及聲音。

UnloadContent 稱為在遊戲結束,而且可讓您卸載您的內容中。 但是,為您處理大部分的影像和音效的卸載,因為您通常不需要執行以下任何動作。

更新程式,可能是其中遊戲開發不同最一般的應用程式開發的地方。 而不是訊息迴圈,遊戲定期輪詢的輸入,計算什麼與它,以及然後畫出這些計算的結果。 大部分的更新,發生,因此這是居住大部分的程式碼。

繪製稱為每個更新之後,而且是您繪製影像的位置中。

就是這樣。 即使程式是很短的它啟動、 會繪製藍色螢幕,會讀取輸入,並結束,當您叫用 [上一步] 按鈕時。 什麼的? 沒有您認為遊戲開發會硬碟嗎? 不是使用 XNA 為遊戲 Studio。

Pixie 灰塵的小精靈

簡單,但吸引人的遊戲,不會進行藍色的背景,結束。 如果您要有一個遊戲,您需要實際的影像。 謝天謝地,螢幕將圖片沒有困難。

稍後我將告訴您的程式碼,但是您必須先載入影像至您的專案中。 在 Visual Studio,您應該會有 「 呼叫 [方案總管] 視窗 (如果您不,您可以找到它在 [檢視] 功能表下)。 在 [方案總管] 中,在 [內容] 上按一下滑鼠右鍵],然後選取 [新增] | 現有的項目。 從這裡您可以指向任何.bmp、.jpg、.png、.tga 或.dds 的影像檔。

讓我們假設有稱為 Player.jpg 和您只要加入該內容的使用者的圖片中。 [圖 1 ] 顯示程式碼在螢幕上顯示該影像。

[圖 1 顯示的影像

// Add these member variables
Texture2D texture;
Vector2 position;

// Add this line to the constructor
position = new Vector2(100, 100);

// Add this line to LoadContent()
texture = Content.Load<Texture2D>("player");

// And add these lines to Draw();
spriteBatch.Begin();
spriteBatch.Draw(texture, position, Color.White);
// (Draw the rest of your sprites)
spriteBatch.End();

我會說明這些行之前,讓我們談術語。 XNA 遊戲 Studio 啟動 Xbox 開發系統。 因此,它是所有根據 3D 圖形。 2D 遊戲 (而且,因為在 Zune 沒有 3D 的產生器,您需要 2D 遊戲) 是真的 3D 遊戲,一切都是真正的精簡型。 因此您會看到 sprinkled 您的程式碼周圍的 3D 文字。 執行個體,精靈時 2D 遊戲中影像的一般詞彙 Word 紋理來自 3D 遊戲。 為目前 XNA 遊戲 Studio 關於,sprite 是真正的精簡型的 3D 矩形,以對應至它們的紋理。

content.load 函的資產名稱,預設是不含副檔名的檔案名稱。 因為我載入影像呼叫 Player.jpg,我傳遞字串 「 Player 至 content.load。 在 LoadContent 函式,您會發現還有已配置一個 SpriteBatch 行。 這個 SpriteBatch 是完成所有的繪圖。 在繪圖函式,您知道在 SpriteBatch 您即將開始,繪製所有小精靈,然後告訴它您完成。

位置的成員變數會是包含 X 的向量結構和您要繪製 sprite 的 y 位置。 在範例中,我會使用像素 (100,100) 的位置。 色彩,就是您可以將您的小精靈加入一個濃淡。 使用泛空白字元會保留未變更的影像。

所以,取得影像,在螢幕上,您就需要載入紋理中,並告訴精靈批次來繪製它。 第一個圖像基本上會使用四行程式碼,],而每個後續一個會使用兩個。

資產名稱的色彩鍵

希望,此時您要查看您的播放程式影像,在螢幕上並想這並非如此困難。 但是或許您可以不完全滿意。 如果您不喜歡的程式碼需要使用影像的檔案名稱嗎? 和,更重要的是如果您載入的圖片矩形,但播放程式沒有? 您如何可以繪製只播放程式和不背景?

若要回答這些問題兩個,您需要查看您載入的影像的屬性。 返回至 [方案總管],並在檔案 (在我範例 Player.jpg) 上按一下滑鼠右鍵。 選取 [內容]。 [內容] 窗格,會出現下列 [方案總管],提供您許多有用的資訊。 先查看資產的名稱。 這是您傳遞給 content.load 名稱。 如果想要讓它以外的檔案名稱,請在此變更。

按一下一點 + 左邊的名稱,現在要展開內容的處理器。 您很在意這裡屬性是的色彩索引鍵的色彩。 任何的像素的色彩會符合色彩索引鍵將會是透明的。 這是您如何取得一個矩形影像,並從背景刪除。 所以,除去您 sprite 的背景,變更其色彩或變更色彩金鑰設定,使其符合。 在設定將預設紅色、 綠色、 藍色,和 255,0,255,255,Alpha 值即洋紅色。

你得移動到播放

當然藍色的背景上單一 sprite 不是要遊戲的下一個大的東西。 最小,您需要使用者能夠以某種方式移動該精靈。 若要這麼做時,您需要知道使用者想要執行的。 如果您已看過更新函式,在程式中,您可能已經瞭解如何執行這項操作。 預設的程式碼會讀取輸入,並結束如果按下返回鍵。 不幸的是,它們的 monopolized 有的輸入。 讓我們變更一個位元,讓您使用以及的輸入項目。

以下是您目前看到的:

if (GamePad.GetState(PlayerIndex.One).Buttons.Back == 
    ButtonState.Pressed)
    this.Exit();

我建議變更它看起來像這樣:

GamePadState input = 
    GamePad.GetState(PlayerIndex.One);
if (input.Buttons.Back == ButtonState.Pressed)
    this.Exit();

現在您可以使用輸入的變數,來查看使用者輸入。 請注意輸入一個 GamePadState。 Zune 的輸入視為的 Xbox 遊戲板的遺失的某些按鈕。 [圖 2 的 Zune 的按鈕] 提供對應的完整清單。

[圖 2 Zune 按鈕對應
按鈕 對應
備份 GamePadState.Buttons.Back
播放 / 暫停 GamePadState.Buttons.B
了方向鍵中心 GamePadState.Buttons.A
了方向鍵邊緣 GamePadState.DPad
滑動,ZunePad 上 GamePadState.Thumbsticks.Left
按一下 [ZunePad GamePadState.Buttons.LeftShoulder

好,我們讓播放程式移動。 [圖 3 ] 中的程式碼涵蓋了方向鍵和 ZunePad 的輸入,因此它在任何 Zune 上運作。 (原始的 Zunes 沒有有 ZunePad 功能)。

[圖 3 支援移動

// add these lines to Update()
const int c_speedScalar = 100;
Vector2 speed = Vector2.Zero;

speed.X = input.ThumbSticks.Left.X * c_speedScalar;
speed.Y = input.ThumbSticks.Left.Y * c_speedScalar * -1;

if (input.DPad.Left == ButtonState.Pressed)
    speed.X -= c_speedScalar;
else if (input.DPad.Right == ButtonState.Pressed)
    speed.Y += c_speedScalar;

if (input.DPad.Up == ButtonState.Pressed)
    speed.Y -= c_speedScalar;
else if (input.DPad.Down == ButtonState.Pressed)
    speed.Y += c_speedScalar;

position += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;

請記住,繪製常式將在位置成員變數所指定位置中繪製播放程式。 所以,移到精靈您需要做的就是更新的位置。

真的花俏的部分是最後一個,您可以變更位置。 Xbox 具有強大的圖形功能,比在的 Zune 的因此更頻繁地呼叫其更新常式。 也就是說,它具有較高的 framerate。 這表示您需要進行獨立的 framerate 的移動。 若要完成這個工作會使用輸入來計算資料的速度不位置。 乘以的自上次呼叫以更新已傳遞的時間,然後轉換速度到的位置。

精靈在方塊中

任何人都可以移動。 秘訣知道何時停止。

如果您的遊戲即將有趣,然後您需要知道一個精靈與另一個的衝突時。 花俏的遊戲開發人員的詞彙,此為衝突偵測,而在 XNA 遊戲 Studio 碰撞偵測,簡單的方法是使用物件呼叫一個 BoundingBox]。 基本上,您您的物件周圍包裝不可見的方塊,並再檢查任何的這些方塊是否交集與彼此。

除了從目前的遊戲的小於令人興奮,最大問題會是精靈可以將移出螢幕。 讓我們來修正的問題。 精靈會叫用的邊緣時, 我們會變得跳回 (100,100) 的位置。

首先,您必須在週框 (Bounding Rectangle) 方塊螢幕:

// Add this member variable
BoundingBox bbScreen;

// Add these lines to Initialize() 
Vector3 min = new Vector3(0, 0, 0);
Vector3 max = new Vector3(graphics.GraphicsDevice.Viewport.Width,
    graphics.GraphicsDevice.Viewport.Height, 0);
bbScreen = new BoundingBox(min, max);

有有點的魔法這裡,但不是很複雜的魔法。 Hello World Framework 提供給您呼叫圖形包含在遊戲螢幕的高度和寬度,在成員變數。 您可以設定螢幕的週框方塊右上角的左上角和右下螢幕的週框方塊至右下角。 BoundingBoxes 會需要 3D 向量,因此設定為 0 的 Z 座標。

現在讓我們建立的的精靈方塊就像這樣:

// Add these lines to Update() after 
// the position has been calculated.
Vector3 min = 
    new Vector3((int)position.X, (int)position.Y, 0);
Vector3 max = 
    new Vector3((int)position.X + texture.Width - 1,
    (int)position.Y + texture.Height - 1, 0);
BoundingBox bb = new BoundingBox(min, max);

最後,讓我們看看精靈是否完全包含在畫面。 如果沒有它必須具有叫用的邊緣。 新增下方先前加入的這些幾行:

ContainmentType ct = bbScreen.Contains(bb);
if (ct != ContainmentType.Contains)
    position = new Vector2(100, 100);

現在,精靈會跳回 (100,100) 時叫用螢幕的邊緣。 您的不用說應該可能執行更具智慧,像停止或扭曲至其他端的內容。

colliding 的螢幕緣的所有點不同 colliding 與另一個物件。 正常的情況是,時,您在螢幕,但您以外的其他物件。 所以,檢查螢幕的邊緣與發生衝突要查看是否在螢幕的方塊會包含您。 但如果要檢查與另一個物件衝突要查看與您是否與該物件的方塊交集。 為了,BoundingBox 物件會具有一個 Intersects 成員函式。 交集傳回 bool,為 true 時,兩個方塊的交集。 如果您想要檢查兩個 sprite 命中彼此,請使用 [Intersects]。

Bing 就 Boom

您現在離開撰寫您自己的遊戲的一種技術。 您可以在繪製影像,這些回應移動的使用者輸入,] 和 [動作在其上執行到彼此。 由於這是遊戲,您可能需要在大型的爆炸結束精靈發生衝突。 已經知道如何繪製在的爆炸但它不會真的 Satisfying 除非太 rattle 玩家的喇叭。 幸運的是,播放音效會比繪製 sprite 更容易。

先,您要將音效加入至專案。 以下的程序很類似加入的影像。 請移至在 [方案總管中上, 按一下滑鼠右鍵內容,並選擇 [新增] | 現有的項目。 從那裡您可以選擇.wav、.wma、.mp3 或.xap 檔案。 而且,影像檔案中,如果您要以不同的資產名稱比檔案名稱,您可以變更它在屬性中。

現在讓我們來播放的音效。 此程式碼會假設您載入的檔案已 explode.wav:

// Add this member variable
SoundEffect sndBoom;

// Add these lines to LoadContent()
ContentManager contentManager = 
    new ContentManager(Services, "Content");
sndBoom = 
    contentManager.Load<SoundEffect>("explode");

// Add these lines to Update()
if (input.Buttons.B == ButtonState.Pressed)
    sndBoom.Play();

contentManager.load 呼叫很類似,您用來載入您的 sprite 的紋理的函式中。 然後,如,您希望聽到的聲音您只要播放它。 請注意,寫入,這個程式碼會嘗試播放新的音效每個框架 [B] 按鈕被按下時。 根據播放聲音的長度,這可能導致它播放和您的遊戲擲回例外狀況的有太多的複本。 您應該防止,每一按鈕的按下,播放一次。 在傳統来這麼做就是儲存先前的狀態的輸入] 和 [動作狀態變更時只。

進階繪圖

您現在有基本的工具,您需要建置您自己的遊戲。 我建議您花點時間使用這些工具所播放,並取得熟悉它們。 當您準備如需詳細資訊時,您可以參閱本節進階概念的簡介。 說明文件,這些函式會提供您需知道要使用它們的一切項目。

先,讓我們談 Z 順序。 為程式碼目前代表,如果兩個 sprite 重疊的繪製的最後一個最後會在最上面。 這種痛苦。 更好方法,是給每個 sprite 變數,指出在其中應該要繪製的順序。 若要這樣做,您需要使用更複雜的版本,spriteBatch.begin 的 spriteBatch.Draw,就像這樣:

spriteBatch.Begin(
    SpriteBlendMode.AlphaBlend, 
    SpriteSortMode.BackToFront, 
    SaveStateMode.None);
spriteBatch.Draw(texture, position, 
    null, Color.White, 0, Vector2.Zero, 
    1.0F, SpriteEffects.None, zOrder);

花點時間 SpriteBatch 文件和實驗。 這些函式是有點複雜,但是它們可以也非常強大。 例如,如果要變更您的小精靈的大小您可以使用矩形而非向量的位置。 矩形界限不同紋理的大小是否 XNA 遊戲 Studio 將會調整它為您自動。 您的紋理是否要循環之間的多個影像您將可以在來源矩形,指定要繪製紋理的哪個部分中傳遞。

如果您希望半透明的 sprite,請變更您傳遞至繪製的色彩的 Alpha 值:

Color trans = new Color(
    Color.White.R, Color.White.G, 
    Color.White.B, 128);

繪製,而非 color.white,和精靈的傳遞 Trans 是半半透明。

最後,如下一些很棒的程式碼可用來旋轉橫向模式從縱向螢幕:

// Add this member variable
Matrix matTransform;

// Add these lines to the constructor
matTransform = Matrix.Identity;
matTransform *= 
    Matrix.CreateRotationZ(MathHelper.ToRadians(90));
matTransform *= 
    Matrix.CreateTranslation(240, 0, 0);

// In Draw() change spriteBatch.Begin to this
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, 
    SpriteSortMode.BackToFront, SaveStateMode.None, 
    matTransform);

其餘部分就是您 Up To

完整我的範例程式碼會顯示在 [圖 4 ,並且應該取得您移動]。 如果執行 aground Creators.xna.com 網站將是完整的範例,顯示如何執行各種難懂的遊戲開發項目,從每個像素週框 (Bounding Rectangle) 方塊物理模型。

[圖 4 A 簡單 Zune 遊戲

public class Game1 : Microsoft.Xna.Framework.Game {
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    Matrix matTransform;
    Texture2D texture;
    SoundEffect sndBoom;
    BoundingBox bbScreen;
    Vector2 position;

    public Game1() {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        position = new Vector2(100, 100);
        matTransform = Matrix.Identity;
        // Uncomment these lines to do Landscape Mode
        //matTransform *= Matrix.CreateRotationZ(          MathHelper. ToRadians(90));
        //matTransform *= Matrix.CreateTranslation(240, 0, 0);
    }

    protected override void Initialize() {
        Vector3 min = new Vector3(0, 0, 0);
        Vector3 max = 
            new Vector3(
            graphics.GraphicsDevice.Viewport.Width, 
            graphics.GraphicsDevice.Viewport.Height, 0);
        bbScreen = new BoundingBox(min, max);
        base.Initialize();
    }

    protected override void LoadContent() {
        spriteBatch = new SpriteBatch(GraphicsDevice);
        texture = Content.Load<Texture2D>("player");
        ContentManager contentManager = 
            new ContentManager(Services, @"Content\Audio");
        sndBoom = contentManager.Load<SoundEffect>("explode");
    }

    protected override void UnloadContent() {
    }

    protected override void Update(GameTime gameTime) {
        GamePadState input = GamePad.GetState(PlayerIndex.One);
        if (input.Buttons.Back == ButtonState.Pressed)
            this.Exit();

        if (input.Buttons.B == ButtonState.Pressed)
            sndBoom.Play();

        const int c_speedScalar = 100;
        Vector2 speed = Vector2.Zero;

        speed.X = input.ThumbSticks.Left.X * c_speedScalar;
        speed.Y = input.ThumbSticks.Left.Y * c_speedScalar * -1;

        if (input.DPad.Left == ButtonState.Pressed)
            speed.X -= c_speedScalar;
        else if (input.DPad.Right == ButtonState.Pressed)
            speed.X += c_speedScalar;

        if (input.DPad.Up == ButtonState.Pressed)
            speed.Y -= c_speedScalar;
        else if (input.DPad.Down == ButtonState.Pressed)
            speed.Y += c_speedScalar;

        position += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;

        Vector3 min = new Vector3((int)position.X, (int)position.Y, 0);
        Vector3 max = new Vector3((int)position.X + 
            texture.Width - 1, (int)position.Y + texture.Height - 1, 0);
        BoundingBox bb = new BoundingBox(min, max);

        ContainmentType ct = bbScreen.Contains(bb);
        if (ct != ContainmentType.Contains)
            position = new Vector2(100, 100);

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime) {
        GraphicsDevice.Clear(Color.CornflowerBlue);
        spriteBatch.Begin(SpriteBlendMode.AlphaBlend, 
            SpriteSortMode.BackToFront, SaveStateMode.None, matTransform);
        spriteBatch.Draw(texture, position, null, Color.White, 
            0, Vector2.Zero, 1.0F, SpriteEffects.None, 0.5F);
        spriteBatch.End();

        base.Draw(gameTime);
    }
}

我希望您會在 C# 是一樣中找到 XNA 遊戲開發 Fun 像我一樣。也許您撰寫的項目將會變成遊戲的下一個大的東西...如果我的兒子不打敗給它。快樂的程式碼撰寫。

您問題或意見寄至goplaces@Microsoft.com.

Mike Calligaro 是與 Windows Mobile 小組在 Microsoft 和參與者至 Windows Mobile 小組的部落格,您可以看到在為資深開發領導人blogs.msdn.com/windowsmobile.