天天看點

【用C#寫遊戲-XNA遊戲程式設計】坦克大戰(一) 初探XNA

    從初涉程式設計到學習C#也一年有餘了,從今天開始就借一個《坦克大戰》來對自己以前學過的知識進行一次彙總和嘗試開始寫部落格,好了,廢話不多說,開篇。

    XNA中的X表示能夠在WindowsXbox和合作夥伴之間達到跨平台的強大的軟體工具。N表示“下一代(Next-generation)”,A表示“架構(Architecture)”。XNA是基于DirectX的遊戲開發環境,是微軟對于 Managed DirectX 的修正及擴充版本。

    以上抄自百度百科,XNA現在确實比較少人用,微軟貌似也不打算更新了,XNA現在的最高版本依舊還是4.0,但這個沒關系,反正用XNA的目的隻是為了鞏固下自己的基礎知識而已,所有用XNA來寫在适合不過了,其中原因有幾點:

    1.還是依舊熟悉的C#語言 (這完全廢話不解釋 = =

    2.可以對一個遊戲的編寫有一個系統的了解,用unity開發估計會簡單很多、但不有利于知識的彙總

    3.畢竟下來要寫的是我們兒時經常玩的《小坦克大戰》,XNA搞2d還是很友善的

    如果是單純想學習遊戲開發希望能找份好工作的話就不推薦搞這個了,壓根就沒人用、工作崗位太少了,當然我的本意也隻是為了鞏固下知識,和初步了解下看看究竟這個"遊戲開發”到底是個什麼玩意; (當然遊戲開發還是大大推薦Unity,無論是做2d還是3d,這個遊戲引擎都是非常友善和好用!

    好,現在開始看看XNA的項目模闆都有些什麼東西吧! (要安裝XNA Game Studio後才能找到XNA的項目模闆

    建立一個名為TankeWar的WIndows遊戲項目

【用C#寫遊戲-XNA遊戲程式設計】坦克大戰(一) 初探XNA

    vs自動幫我們多建立了一個名為"TankeWarContent“的内容項目,這個項目就是專門用來放遊戲資源的,例如一些遊戲貼圖、音樂什麼的,現在看下Gmae1.cs裡面都有些什麼吧。

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace TankeWar
{
    /// <summary>
    /// 這是遊戲的主類型
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// 允許遊戲在開始運作之前執行其所需的任何初始化。
        /// 遊戲能夠在此時查詢任何所需服務并加載任何非圖形
        /// 相關的内容。調用 base.Initialize 将枚舉所有元件
        /// 并對其進行初始化。 
        /// </summary>
        protected override void Initialize()
        {
            // TODO: 在此處添加初始化邏輯

            base.Initialize();
        }

        /// <summary>
        /// 對于每個遊戲會調用一次 LoadContent,
        /// 用于加載所有内容。
        /// </summary>
        protected override void LoadContent()
        {
            // 建立新的 SpriteBatch,可将其用于繪制紋理。
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: 在此處使用 this.Content 加載遊戲内容
        }

        /// <summary>
        /// 對于每個遊戲會調用一次 UnloadContent,
        /// 用于取消加載所有内容。
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: 在此處取消加載任何非 ContentManager 内容
        }

        /// <summary>
        /// 允許遊戲運作邏輯,例如更新全部内容、
        /// 檢查沖突、收集輸入資訊以及播放音頻。
        /// </summary>
        /// <param name="gameTime">提供計時值的快照。</param>
        protected override void Update(GameTime gameTime)
        {
            // 允許遊戲退出
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: 在此處添加更新邏輯

            base.Update(gameTime);
        }

        /// <summary>
        /// 當遊戲該進行自我繪制時調用此項。
        /// </summary>
        /// <param name="gameTime">提供計時值的快照。</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: 在此處添加繪圖代碼

            base.Draw(gameTime);
        }
    }
}
           

    模闆幫咱們生成好的代碼已經有很詳細的注釋了,詳細也不用我廢話什麼了,但它們的生命周期還是要說一下:遊戲開始後會先Initialize()方法、然後到LoadContent()方法加載遊戲資源、然後就到Update()和Draw()這兩個主要的遊戲循環,但這兩個也有先後順序的,先Update()後Draw()、最後遊戲收到退出指令後執行UnloadContent()釋放所有遊戲資源;

    好勒,既然對XNA的結構有了大緻的了解後,咱就開搞了、先試試讓咱們的小坦克在遊戲裡面動起來!

    既然是坦克大戰、沒坦克還玩個鳥,咱先到網上搜羅幾張坦克大戰的遊戲貼圖回來先,然後把貼圖添加到TankeWarContent項目裡面,像這樣:

【用C#寫遊戲-XNA遊戲程式設計】坦克大戰(一) 初探XNA

    好了,現在素材也有了,開始敲代碼吧

    先定義一個小坦克的紋理對象:

GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D TankeTexture2D;   //定義一個小坦克的2D紋理對象

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
           

    然後在LoadContent()資源加載方法内把圖檔給加載到TankeTexture2D對象裡面去:

protected override void LoadContent()
        {
            // 建立新的 SpriteBatch,可将其用于繪制紋理。
            spriteBatch = new SpriteBatch(GraphicsDevice);
            TankeTexture2D = Content.Load<Texture2D>("p1tank0");    //加載圖檔資源
            // TODO: 在此處使用 this.Content 加載遊戲内容
        }
           

    最後把紋理對象畫到螢幕裡面:

protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: 在此處添加繪圖代碼            

            //把小坦克畫到遊戲螢幕上面
            spriteBatch.Begin();
            spriteBatch.Draw(TankeTexture2D, Vector2.Zero, Color.White);    
            spriteBatch.End();

            base.Draw(gameTime);
        }
           

    按下F5,不出意外的話應該能看到咱們的小坦克出現在螢幕上了,但這個時候按什麼按鍵小坦克都不會動,沒關系,繼續寫代碼:

    在添加多兩個變量,一個是坦克的坐标和坦克移動速度:

GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D TankeTexture2D;   //定義一個小坦克的2D紋理對象
        Vector2 TankePos;           //定義一個小坦克的坐标
        int MoveSpeed = 5;          //定義小坦克移動的速度,預設值為5

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
           

    Update()方法裡面也添加檢測鍵盤的狀态:

protected override void Update(GameTime gameTime)
        {
            // 允許遊戲退出
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            if (Keyboard.GetState().IsKeyDown(Keys.W))
                TankePos.Y -= MoveSpeed;
            if (Keyboard.GetState().IsKeyDown(Keys.S))
                TankePos.Y += MoveSpeed;
            if (Keyboard.GetState().IsKeyDown(Keys.A))
                TankePos.X -= MoveSpeed;
            if (Keyboard.GetState().IsKeyDown(Keys.D))
                TankePos.X += MoveSpeed;

            // TODO: 在此處添加更新邏輯

            base.Update(gameTime);
        }
           

   Draw()也改一改,把出現的固定坐标換成TankePos:

protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: 在此處添加繪圖代碼            

            //把小坦克畫到遊戲螢幕上面
            spriteBatch.Begin();
            //spriteBatch.Draw(TankeTexture2D, Vector2.Zero, Color.White);
            spriteBatch.Draw(TankeTexture2D, TankePos, Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }
           

    再按下F5,按WSAD,哈哈,小坦克是不是會動啦!!    等等,你TM在逗我!? 不管怎麼移動,坦克的炮管為毛都是向上!?

    額....... 其實這個也不難解決的,spriteBatch.Draw()有多個重載,其中就有改變貼圖的角度的,但最簡單的方法就是有4張貼圖、4個紋理對象,按照不同的方向把不同的紋理畫到螢幕上就是了;不過這個以後再說吧,今就到這,往後再慢慢寫。 (今總算是把這坑給開了 = =!