XNA學習筆記3:建立自訂精靈類

來源:互聯網
上載者:User

                                           建立自訂精靈類

            前面我們已經能建立精靈和動畫,並且對精靈執行輸入控制(滑鼠和鍵盤),但是也許我們縱觀上一節那個程式,發現變數種類繁多不利於管理,各種控制語句都在update方法裡面,如果有幾十個精靈,那這個程式豈不是臃腫不堪,所以我們就需要自訂精靈類,讓各種精靈有序的工作,分門別類的進行管理,在XNA中還有一些遊戲組件,這些組件更加方便了我們的管理,遊戲組件將在下一節介紹,由於本節內容十分重要,所以為分為了兩節!


       在我們的遊戲精靈中,雖然有很多精靈,但是說白了就只有兩個種類,一個 使用者控制的(如角色),一個是自動的(如敵人),但是這些精靈都擁有很多相同的屬性,例如都會移動,都有座標,都要繪製,都要更新,經過總結,他們的關係層次圖如下:

所以在這裡我們先在項目中添加一個新類,命名為Sprite,右鍵點擊項目選項-添加-類,並且在sprite.cs中加入這樣的包,以便使用XNA的功能

using Microsoft.Xna.Framework;using Microsoft.Xna.Framework.Graphics;

另外由於這個類只是基類,不是實際的類,所以我們修改他的類屬性為抽象 abstract屬性!

接下來就是要給類新增成員變數了,那麼該添加些什麼勒?我們在前面已經用到了很多了,這裡貼出代碼:

        Texture2D textureImage;                                //各種精靈屬性的成員變數        protected Point frameSize;        Point currentFrame;        Point sheetSize;        int collisionOffset;         int timeSinceLastFrame = 0;        int millisecondsPerFrame;        const int defaultMillisecondsPerFrame = 16;        protected Vector2 speed;         protected Vector2 position;

可以看到類成員變數中有 位元影像,控制精靈位元影像輸出的三個point變數,控制精靈的幀率,速度,當前位置等等變數,應有盡有,這些都記載了精靈的屬性,其中一些有預設值,一些沒有,而且一些為protected屬性,這是為了子類更好的使用,接下來看看我們的建構函式:

public sprite(Texture2D textureImage,                  //建構函式1,有預設參數            Vector2 position,            Point frameSize,             int collisionOffset,            Point currentFrame,            Point sheetSize,            Vector2 speed)  : this(textureImage,            position, frameSize,             collisionOffset,             currentFrame,            sheetSize, speed,            defaultMillisecondsPerFrame) { }        public sprite(Texture2D textureImage,                   //建構函式2,沒有預設參數            Vector2 position,            Point frameSize,            int collisionOffset,            Point currentFrame,            Point sheetSize,            Vector2 speed,            int millisecondsPerFrame)        {            this.textureImage = textureImage;            this.position = position;            this.frameSize = frameSize;            this.collisionOffset = collisionOffset;            this.currentFrame = currentFrame;            this.sheetSize = sheetSize;            this.speed = speed;            this.millisecondsPerFrame = millisecondsPerFrame;        }

兩個建構函式,一個是有預設參數的,一個是沒有預設參數的,接下來看看該類需要什麼方法:

public virtual void Update(GameTime gameTime, Rectangle clientBounds)     //精靈的繪製更新函數        {            timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;             if (timeSinceLastFrame > millisecondsPerFrame)             {                timeSinceLastFrame = 0; ++currentFrame.X;                if (currentFrame.X >= sheetSize.X)                 {                     currentFrame.X = 0;                    ++currentFrame.Y;                     if (currentFrame.Y >= sheetSize.Y)                        currentFrame.Y = 0;                }            }        }

這是update方法,就跟我們在Game類update方法中的一樣,進行精靈位元影像的位置更新,設計為虛函數是為了可以被子類重寫,另外參數列表中也多添加了一個矩形類的變數,這是為了在碰撞檢測的時候使用的!

public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)     //draw方法中需要spritebatch對象,所以需要傳遞        {            spriteBatch.Draw(textureImage, position,                 new Rectangle(currentFrame.X * frameSize.X,                     currentFrame.Y * frameSize.Y, frameSize.X, frameSize.Y),                Color.White, 0, Vector2.Zero, 1f, SpriteEffects.None, 0);         }

這是我們的精靈類的draw方法,就是拷貝的原Game類的draw方法,繪製出精靈,由於在Game中已經有一個SpriteBatch變數,我們這裡沒有,所以需要傳遞一個spriteBatch變數,在繪製的時候使用!

public Rectangle collisionRect                                            //返回精靈的封裝矩形,用於碰撞檢測        {            get            {                return new Rectangle((int)position.X + collisionOffset,                    (int)position.Y + collisionOffset,                     frameSize.X - (collisionOffset * 2),                     frameSize.Y - (collisionOffset * 2));            }        } 

該方法返回精靈的封裝矩形,在碰撞檢測的時候需要

public abstract Vector2 direction                                         //精靈移動方向,子類都不相同,所以應該設定成抽象        {             get;        }

該方法為direction的訪問器,擷取精靈的移動方向,具體如何使用稍後會講!

好了,我們的精靈基類就設計完成了,下面我們開始設計我們的角色類!


2:設計使用者控制的角色類

同樣的方法建立一個類,註明繼承自Sprite類,並且添加XNA的包,與上面不同的是這裡需要該類擷取到使用者的控制,所以還要多加一行

using Microsoft.Xna.Framework.Input;

這行就可以提供擷取使用者輸入的控制,然後添加建構函式,幾乎都跟基類一樣,一個一個賦值而已!

public UserControlledSprite(               //帶預設參數的建構函式 調用了基類建構函式            Texture2D textureImage,            Vector2 position,            Point frameSize,            int collisionOffset,            Point currentFrame,            Point sheetSize,             Vector2 speed) : base(textureImage,            position,            frameSize,            collisionOffset,            currentFrame,            sheetSize,            speed)        { }        public UserControlledSprite(               //一般的建構函式 調用了基類建構函式            Texture2D textureImage,            Vector2 position,            Point frameSize,            int collisionOffset,            Point currentFrame,            Point sheetSize,            Vector2 speed,            int millisecondsPerFrame) : base(            textureImage,            position,            frameSize,            collisionOffset,            currentFrame,            sheetSize,            speed,            millisecondsPerFrame)        { } 

接下來先實現基類中的抽象方法drection:

public override Vector2 direction                            //遊戲方向的確定,由使用者輸入和自訂的速度共同決定        {            get            {                Vector2 inputDirection = Vector2.Zero;                if (Keyboard.GetState( ).IsKeyDown(Keys.Left))                    inputDirection.X -= 1;                if (Keyboard.GetState( ).IsKeyDown(Keys.Right))                    inputDirection.X += 1;                if (Keyboard.GetState( ).IsKeyDown(Keys.Up))                    inputDirection.Y -= 1;                if (Keyboard.GetState( ).IsKeyDown(Keys.Down))                    inputDirection.Y += 1;                   return inputDirection * speed;            }        }

這個方向向量表示了精靈的移動距離,在以前我們按下左鍵精靈直接移動2,按多少次就移動多少個2,這樣就無法中途更改移動速度,所以這裡用方向乘以速度來決定位移量,如果沒有按鍵,返回的是0!

public override void Update(GameTime gameTime, Rectangle clientBounds)        {                            position += direction;                           MouseState currMouseState = Mouse.GetState( );                   //滑鼠控制 就不在使用方向了            if (currMouseState.X != prevMouseState.X ||   currMouseState.Y != prevMouseState.Y)            {                position = new Vector2(currMouseState.X, currMouseState.Y);            }            prevMouseState = currMouseState;                          if (position.X < 0)                                              //保持精靈始終在視窗中間                position.X = 0;             if (position.Y < 0)                position.Y = 0;            if (position.X > clientBounds.Width - frameSize.X)            {                position.X = clientBounds.Width - frameSize.X;            }            if (position.Y > clientBounds.Height - frameSize.Y)            {                position.Y = clientBounds.Height - frameSize.Y;            }              base.Update(gameTime, clientBounds);        } 

這裡我們也知道,滑鼠控制是要檢測上一幀滑鼠位置和當前幀有沒有發生改變,所以需要一個prevmousestate變數,這個需要在寫update方法的時候加入到類成員變數中,設為私人的!

由於draw方法不需要做改變,所以我們這裡就不需要重寫draw方法了,現在我們的角色類也就已經寫完了。


3:設計自動的遊戲精靈類

同上建立一個繼承自sprite的類,並且加入XNA的包,這裡不需要使用者輸入,所以可以不加第三個包,

這個類設計很簡單,我就不用多說了

 class AutomatedSprite:sprite    {        public AutomatedSprite            (Texture2D textureImage,            Vector2 position,            Point frameSize,            int collisionOffset,            Point currentFrame,            Point sheetSize,            Vector2 speed)  : base(            textureImage,            position,            frameSize,            collisionOffset,            currentFrame,            sheetSize,            speed) { }                public AutomatedSprite(            Texture2D textureImage,            Vector2  position,            Point frameSize,            int collisionOffset,            Point currentFrame,            Point sheetSize,            Vector2 speed,            int millisecondsPerFrame)  : base(            textureImage,            position,            frameSize,            collisionOffset,            currentFrame,            sheetSize,            speed,            millisecondsPerFrame) { }        public override Vector2 direction        {            get            {                return speed;                          //他沒有方向的控制,傳回值直接就是速度            }        }        public override void Update(GameTime gameTime, Rectangle clientBounds)        {            position += direction;            base.Update(gameTime, clientBounds);               //別忘記調用基類的方法,以便不影響精靈位元影像的更新        }     }

我們的三個類都設計完了,本節的工作也就完成了,為了需要我這裡把前面兩個類的完整代碼貼出來

Sprite類

using System;using System.Collections.Generic;using System.Linq;using System.Text;using Microsoft.Xna.Framework;using Microsoft.Xna.Framework.Graphics;namespace WindowsGame6{    abstract class sprite    {        Texture2D textureImage;                                //各種精靈屬性的成員變數        protected Point frameSize;        Point currentFrame;        Point sheetSize;        int collisionOffset;         int timeSinceLastFrame = 0;        int millisecondsPerFrame;        const int defaultMillisecondsPerFrame = 16;        protected Vector2 speed;         protected Vector2 position;        public sprite(Texture2D textureImage,                  //建構函式1,有預設參數            Vector2 position,            Point frameSize,             int collisionOffset,            Point currentFrame,            Point sheetSize,            Vector2 speed)  : this(textureImage,            position, frameSize,             collisionOffset,             currentFrame,            sheetSize, speed,            defaultMillisecondsPerFrame) { }        public sprite(Texture2D textureImage,                   //建構函式2,沒有預設參數            Vector2 position,            Point frameSize,            int collisionOffset,            Point currentFrame,            Point sheetSize,            Vector2 speed,            int millisecondsPerFrame)        {            this.textureImage = textureImage;            this.position = position;            this.frameSize = frameSize;            this.collisionOffset = collisionOffset;            this.currentFrame = currentFrame;            this.sheetSize = sheetSize;            this.speed = speed;            this.millisecondsPerFrame = millisecondsPerFrame;        }        public virtual void Update(GameTime gameTime, Rectangle clientBounds)     //精靈的繪製更新函數        {            timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;             if (timeSinceLastFrame > millisecondsPerFrame)             {                timeSinceLastFrame = 0; ++currentFrame.X;                if (currentFrame.X >= sheetSize.X)                 {                     currentFrame.X = 0;                    ++currentFrame.Y;                     if (currentFrame.Y >= sheetSize.Y)                        currentFrame.Y = 0;                }            }        }        public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)     //draw方法中需要spritebatch對象,所以需要傳遞        {            spriteBatch.Draw(textureImage, position,                 new Rectangle(currentFrame.X * frameSize.X,                     currentFrame.Y * frameSize.Y, frameSize.X, frameSize.Y),                Color.White, 0, Vector2.Zero, 1f, SpriteEffects.None, 0);         }        public abstract Vector2 direction                                         //精靈移動方向,子類都不相同,所以應該設定成抽象        {             get;        }        public Rectangle collisionRect                                            //返回精靈的封裝矩形,用於碰撞檢測        {            get            {                return new Rectangle((int)position.X + collisionOffset,                    (int)position.Y + collisionOffset,                     frameSize.X - (collisionOffset * 2),                     frameSize.Y - (collisionOffset * 2));            }        }     }}

UserControlledSprite類

using System;using System.Collections.Generic;using System.Linq;using System.Text;using Microsoft.Xna.Framework;using Microsoft.Xna.Framework.Graphics;using Microsoft.Xna.Framework.Input;                //使用者控制的類,需要從裝置擷取資料namespace WindowsGame6{    class UserControlledSprite:sprite    {        private MouseState prevMouseState;        public UserControlledSprite(               //帶預設參數的建構函式 調用了基類建構函式            Texture2D textureImage,            Vector2 position,            Point frameSize,            int collisionOffset,            Point currentFrame,            Point sheetSize,             Vector2 speed) : base(textureImage,            position,            frameSize,            collisionOffset,            currentFrame,            sheetSize,            speed)        { }        public UserControlledSprite(               //一般的建構函式 調用了基類建構函式            Texture2D textureImage,            Vector2 position,            Point frameSize,            int collisionOffset,            Point currentFrame,            Point sheetSize,            Vector2 speed,            int millisecondsPerFrame) : base(            textureImage,            position,            frameSize,            collisionOffset,            currentFrame,            sheetSize,            speed,            millisecondsPerFrame)        { }         public override Vector2 direction                            //遊戲方向的確定,由使用者輸入和自訂的速度共同決定        {            get            {                Vector2 inputDirection = Vector2.Zero;                if (Keyboard.GetState( ).IsKeyDown(Keys.Left))                    inputDirection.X -= 1;                if (Keyboard.GetState( ).IsKeyDown(Keys.Right))                    inputDirection.X += 1;                if (Keyboard.GetState( ).IsKeyDown(Keys.Up))                    inputDirection.Y -= 1;                if (Keyboard.GetState( ).IsKeyDown(Keys.Down))                    inputDirection.Y += 1;                   return inputDirection * speed;            }        }        public override void Update(GameTime gameTime, Rectangle clientBounds)        {                            position += direction;                            MouseState currMouseState = Mouse.GetState( );            if (currMouseState.X != prevMouseState.X ||   currMouseState.Y != prevMouseState.Y)            {                position = new Vector2(currMouseState.X, currMouseState.Y);            }            prevMouseState = currMouseState;                         if (position.X < 0)                position.X = 0;            if (position.Y < 0)                position.Y = 0;            if (position.X > clientBounds.Width - frameSize.X)            {                position.X = clientBounds.Width - frameSize.X;            }            if (position.Y > clientBounds.Height - frameSize.Y)            {                position.Y = clientBounds.Height - frameSize.Y;            }              base.Update(gameTime, clientBounds);        }     }}

下一節我們介紹如何利用遊戲組件,把這些類有機的組合在一起,他們的使用會讓遊戲程式變得那麼的物件導向化!






聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.