XNA 遊戲程式設計 - 2D 的打飛碟遊戲

作品

書籍

課程

程式集

小說集

論文集

散文集

影片集

編輯雜誌

程式人

電子書

JavaScript

計算語言學

微積分

Blender 動畫

C# 語言

系統程式

高等 C 語言

Java

Android

Verilog

Wikidot

R 統計軟體

機率統計

計算機數學

組合語言

人工智慧

開放原始碼

網路資源運用

計算機結構

相關訊息

常用工具

友站連結

在家教育

RSS

最新修改

網頁列表

簡體版

English

程式專案下載 — http://ccckmit.wikidot.com/local--files/xna/2D_FighterGame.zip

簡介

本文介紹如何用微軟的 XNA 遊戲引擎設計一個 2D 的打飛碟遊戲。

在該遊戲中,共有 3 隻飛碟會亂飛,玩家的符號是一個砲台,您必須發射砲彈打飛碟,並且一邊閃避飛碟,每打死一台飛碟就會加一分,一但被飛碟撞到後就會死亡,導致遊戲結束,最後看看你能得到多少分,下圖顯示了遊戲的一個擷取畫面。

GameScreenCatch.jpg

設計方法

XNA 遊戲的主要架構包含載入 (LoadContent)、更新 (Update) 、繪出 (Draw) 等三個動作,以下是本遊戲中的主要程式片斷。

  • 資料結構
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Sprite playerSprite;
        const int MAX_MISSILES = 5, MAX_ENEMIES = 3;
        Sprite[] missileSprites = new Sprite[MAX_MISSILES];
        Sprite[] enemySprites = new Sprite[MAX_ENEMIES];
        Vector2 screenSize;
        Texture2D playerTexture, enemyTexture, missileTexture;
        KeyboardState previousKeyboardState = Keyboard.GetState();
        bool isGameOver = false;
        Random random = new Random();
        SpriteFont font;
        int score = 0;
  • 載入資源 (圖檔+字型)
        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
            screenSize = new Vector2(graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height);
            playerTexture = Content.Load<Texture2D>("player");
            enemyTexture = Content.Load<Texture2D>("enemy");
            missileTexture = Content.Load<Texture2D>("missile");

            playerSprite = new Sprite(playerTexture, new Vector2(300, 400));
            playerSprite.size.Y = 140;
            for (int i = 0; i < MAX_MISSILES; i++)
            {
                missileSprites[i] = new Sprite(missileTexture, new Vector2(0, 0));
                missileSprites[i].isAlive = false;
            }
            for (int i = 0; i < MAX_ENEMIES; i++)
            {
                enemySprites[i] = new Sprite(enemyTexture, randomEnemyXY());
                enemySprites[i].velocity = new Vector2(random.Next(-3, 3), random.Next(-3, 3));
                enemySprites[i].isAlive = false;
            }

            font = Content.Load<SpriteFont>("SpriteFont");
            base.LoadContent();
        }

        public Vector2 randomEnemyXY() 
        {
           int enemyX = random.Next(0, (int) (screenSize.X-100) );
           int enemyY = random.Next(0);
           return new Vector2(enemyX, enemyY);
        }
  • 更新邏輯模型
        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
            if (isGameOver) return;
#if !XBOX
            KeyboardState keyboardState = Keyboard.GetState();
            if (keyboardState.IsKeyDown(Keys.Left))  playerSprite.velocity = new Vector2(-5, 0);
            if (keyboardState.IsKeyDown(Keys.Right)) playerSprite.velocity = new Vector2(5, 0);
            if (keyboardState.IsKeyDown(Keys.Up)) playerSprite.velocity = new Vector2(0, -5);
            if (keyboardState.IsKeyDown(Keys.Down)) playerSprite.velocity = new Vector2(0, 5);
            if (keyboardState.IsKeyDown(Keys.Space) && previousKeyboardState.IsKeyUp(Keys.Space))
            {
                float x = playerSprite.position.X + playerTexture.Width/2 - missileTexture.Width/2;
                float y = playerSprite.position.Y;
                fireMissile(x, y);
            }
            previousKeyboardState = keyboardState;
#endif
            Rectangle playerRect = new Rectangle((int)playerSprite.position.X + 20, (int)playerSprite.position.Y + 20,
                                                 playerTexture.Width-40, playerTexture.Height/2);
            foreach (Sprite enemy in enemySprites) 
            {
                if (!enemy.isAlive)
                {
                    enemy.isAlive = true;
                    enemy.position = randomEnemyXY();
                }

                enemy.Move(screenSize);
                Rectangle enemyRect = new Rectangle((int) enemy.position.X+20, (int) enemy.position.Y+20, 
                                                    enemyTexture.Width-40, enemyTexture.Height-40);
                if (enemyRect.Intersects(playerRect))
                    isGameOver = true;

                foreach (Sprite missile in missileSprites)
                {
                    if (missile.isInside(screenSize))
                        missile.Move(screenSize);
                    else
                        missile.isAlive = false;

                    if (missile.isAlive)
                    {
                        Rectangle missileRect = new Rectangle((int) missile.position.X, (int) missile.position.Y, 
                                                              missileTexture.Width, missileTexture.Height);
                        if (missileRect.Intersects(enemyRect))
                        {
                            enemy.isAlive = false;
                            score ++;
                        }
                    }
                }
            }

            playerSprite.Move(screenSize);

            base.Update(gameTime);
        }

        public void fireMissile(float x, float y)
        {
            foreach (Sprite missile in missileSprites)
            {
                if (!missile.isAlive)
                {
                    missile.isAlive = true;
                    missile.position = new Vector2(x, y);
                    missile.velocity = new Vector2(0, -5);
                    return;
                }
            }
        }
  • 繪出 - 更新畫面
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
            playerSprite.draw(spriteBatch);
            foreach (Sprite enemy in enemySprites)
                enemy.draw(spriteBatch);
            foreach (Sprite missile in missileSprites)
            {
                if (missile.isAlive)
                    missile.draw(spriteBatch);
            }
            spriteBatch.DrawString(font, String.Format("Score:{0}", score), new Vector2(10, 10), Color.Black);
            if (isGameOver)
                spriteBatch.DrawString(font, "Game Over!", new Vector2(screenSize.X / 2, screenSize.Y / 2), Color.Black);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }

結語

在本文中,我們示範了如何使用 XNA 設計一個簡單的小遊戲 『打飛碟』。透過這樣的範例,應該可以呈現出 XNA 的 2D 遊戲設計方法,進一部的資訊可參考相關資源。

參考文獻

  1. XNA 遊戲設計課程 — 陳鍾誠的 XNA 遊戲設計課程網頁。
  2. XNA Creator Club Online, Getting Start — http://creators.xna.com/en-US/education/gettingstarted

Facebook

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License