精靈的控制和碰撞檢測
上一節我們瞭解了精靈的繪製,移動以及動畫的實現,並且在最後我們實現了三個環的簡單動畫,今天我們學習下如何通過裝置控制精靈,這一節的內容比較簡單,很好理解,在這裡我先把控制精靈的全部代碼貼上來,方便接下來的學習!
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 WindowsGame6{ public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D ringtexture; //三環動畫的相關變數 Point ringframeSize = new Point(75, 75); Point ringcurrentFrame = new Point(0, 0); Point ringsheetSize = new Point(6, 8); Vector2 ringpos1 = Vector2.Zero; const float ringspeed = 5; Texture2D skulltexture; //骷髏頭動畫相關變數 Point skullframeSize = new Point(75, 75); Point skullcurrentFrame = new Point(0, 0); Point skullsheetSize = new Point(6, 8); MouseState prevmousestate; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void Initialize() { // TODO: 在此處添加初始化邏輯 base.Initialize(); } protected override void LoadContent() { // 建立新的 SpriteBatch,可將其用於繪製紋理。 spriteBatch = new SpriteBatch(GraphicsDevice); ringtexture = Content.Load<Texture2D>("Images//threerings"); //載入兩幅位元影像 skulltexture = Content.Load<Texture2D>("Images//skullball"); // TODO: 在此處使用 this.Content 載入遊戲內容 } protected override void UnloadContent() { // TODO: 在此處取消載入任何非 ContentManager 內容 } protected override void Update(GameTime gameTime) { // 允許遊戲退出 if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); ++ringcurrentFrame.X; //迴圈三環精靈位元影像 if (ringcurrentFrame.X >= ringsheetSize.X) { ringcurrentFrame.X = 0; ++ringcurrentFrame.Y; if (ringcurrentFrame.Y >= ringsheetSize.Y) ringcurrentFrame.Y = 0; } ++skullcurrentFrame.X; //迴圈骷髏精靈位元影像 if (skullcurrentFrame.X >= skullsheetSize.X) { skullcurrentFrame.X = 0; ++skullcurrentFrame.Y; if (skullcurrentFrame.Y >= skullsheetSize.Y) skullcurrentFrame.Y = 0; } // TODO: 在此處添加更新邏輯 KeyboardState keyboardstate = Keyboard.GetState(); //鍵盤控制三環動畫語句 if (keyboardstate.IsKeyDown(Keys.Left)) ringpos1.X -= ringspeed; if (keyboardstate.IsKeyDown(Keys.Right)) ringpos1.X += ringspeed; if (keyboardstate.IsKeyDown(Keys.Up)) ringpos1.Y -= ringspeed; if (keyboardstate.IsKeyDown(Keys.Down)) ringpos1.Y += ringspeed; MouseState mouseState = Mouse.GetState(); //滑鼠控制三環動畫語句 if (mouseState.X != prevmousestate.X || mouseState.Y != prevmousestate.Y) ringpos1 = new Vector2(mouseState.X, mouseState.Y); prevmousestate = mouseState; if (ringpos1.Y < 0) //使三環精靈一直保持在視窗中 ringpos1.Y = 0; if (ringpos1.Y > Window.ClientBounds.Height - ringframeSize.Y) ringpos1.Y = Window.ClientBounds.Height - ringframeSize.Y; if (ringpos1.X < 0) ringpos1.X = 0; if (ringpos1.X > Window.ClientBounds.Width - ringframeSize.X) ringpos1.X = Window.ClientBounds.Width - ringframeSize.X; base.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend); spriteBatch.Draw( //繪製三環精靈 ringtexture,ringpos1, new Rectangle(ringcurrentFrame.X * ringframeSize.X, ringcurrentFrame.Y * ringframeSize.Y, ringframeSize.X, ringframeSize.Y), Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0); spriteBatch.Draw( //繪製骷髏精靈 skulltexture, new Vector2(100,100), new Rectangle(skullcurrentFrame.X * skullframeSize.X, skullcurrentFrame.Y * skullframeSize.Y, skullframeSize.X, skullframeSize.Y), Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0); spriteBatch.End(); // TODO: 在此處添加繪圖代碼 base.Draw(gameTime); } }}
1:更多精靈的繪製
在昨天那個三環精靈程式碼的基礎上,現在我們需要再多加一個精靈位元影像進來,還是老辦法:
這是一副骷髏精靈位元影像,跟三環動畫一樣在類最前面加上那幾行代碼,並且在loadcontent函數中載入位元影像,並且在draw函數中繪製出位元影像,為了不與第一幅重複,我們這裡設定繪製的座標為(100,100),然後運行,可以看到螢幕中有兩個動畫在旋轉!
2:使用鍵盤控制精靈的移動!
這裡需要一點新知識了,鍵盤輸入是通過Microsoft.XNA.Framework.Input命名空間中的Keyboard類來處 理的。Keyboard 類有一個叫做 GetState 的靜態方法,用 KeyboardState 結構的形式返 回鍵盤目前的狀態。
KeyboardState 結構中包含三個能夠滿足您大部分的功能需求的關鍵方法如下:
Keys[] GetPressedKeys() 返回一個在方法被調用時被按下的鍵的數組
bool IsKeyDown(Keys key) 返回 true 或 false,取決於方法調用時參數所代表的 按鍵是否被按下
bool IsKeyUp(Keys key) 返回 true 或 false,取決於方法調用時參數所代表的 按鍵是否被釋放
舉個例子,如果要檢測鍵盤的A鍵是否被按下,則該這樣來寫代碼:
if(Keyboard.GetState( ).IsKeyDown(Keys.A));
好了,現在我們可以來著手實現鍵盤的上下左右控制三環動畫的移動了,這裡跟昨天一樣,需要加一個Vector2的變數ringpos1,並且在draw的方法中改變三環動畫的位置為ringpos1,
接下來就應該在update方法中實現移動的距離更新,代碼如下:
KeyboardState keyboardstate = Keyboard.GetState(); //鍵盤控制三環動畫語句 if (keyboardstate.IsKeyDown(Keys.Left)) ringpos1.X -= ringspeed; if (keyboardstate.IsKeyDown(Keys.Right)) ringpos1.X += ringspeed; if (keyboardstate.IsKeyDown(Keys.Up)) ringpos1.Y -= ringspeed; if (keyboardstate.IsKeyDown(Keys.Down)) ringpos1.Y += ringspeed;
這裡就如同上面貼出來的一樣,我們之所以不用if else,而是用4個if是因為這樣可以同時從兩個方向移動,比如上左,右下,如果改為if else就只能向其中一個方向移動,現在可以編譯運行,使用鍵盤的上下左右,就可以移動我們的三環動畫了!!
3:使用滑鼠控制三環動畫!
XNA 提供了一個和 Keyboard 類行為很相似的 Mouse 類來和滑鼠進行互動。Mouse 類也 有一個 GetState 方法,能以 MouseState 結構的形式從滑鼠返回資料。
MouseState 有一些屬 性將會協助您瞭解到當您調用 GetState 時滑鼠在特定時刻發生了什麼。具體如下:
LeftButton ButtonState 返回滑鼠左鍵的狀態
MiddleButton ButtonState 返回滑鼠中鍵的狀態
RightButton ButtonState 返 回滑鼠右鍵的狀態
ScrollWheelValue int 返回自遊戲開始後滑鼠滾輪滾動刻度的累加量.要想知 道滾輪滾動了多少,把當前幀的ScrollWheelValue和 上一幀的進行比較.
X int 返回滑鼠游標相對於遊戲視窗左上方的水平位置(坐 標).如果滑鼠游標在遊戲視窗的左側,這個值是負值;如 果在遊戲視窗右邊,這個值大於遊戲視窗的寬度
. XButton1 ButtonState 返回某些滑鼠上額外的按鍵的狀態
XButton2 ButtonState 返回某些滑鼠上額外的按鍵的狀態
Y int 返回滑鼠游標相對於遊戲視窗左上方的垂直位置(坐 標).如果滑鼠游標在遊戲視窗的上方,這個 值是負值; 如果在遊戲視窗下方,這個值大於遊戲視窗的高度.
為了確定滑鼠是否被移動,在 Game1 類頂部添加一個類成員變數:
MouseState preMouseState; (如所示)
將以下代碼添加到 Update 方法中,位於 base.Update 方法的調用之前:
MouseState mouseState = Mouse.GetState(); //滑鼠控制三環動畫語句 if (mouseState.X != prevmousestate.X || mouseState.Y != prevmousestate.Y) ringpos1 = new Vector2(mouseState.X, mouseState.Y); prevmousestate = mouseState;
現在編譯運行,則三環動畫會跟著滑鼠走,我們的滑鼠控制也就完成了!
4:使動畫保留在視窗之間
您可能已經注意到了,三環精靈會在您將它移動得足夠遠時消失在螢幕的邊緣。讓玩家控 制的物體能夠離開螢幕並且消失不見永遠不會是一個好主意。要糾正這個問題,您需要在 Update 函數的結尾更新精靈的位置。如果精靈已經向左、向右、向上或向下移動得太遠,更 正它的位置來使其保持在遊戲視窗中。將下面的代碼添加到 Update 方法的末尾,位於 base.Update 方法的調用之前:
if (ringpos1.Y < 0) //使三環精靈一直保持在視窗中 ringpos1.Y = 0; if (ringpos1.Y > Window.ClientBounds.Height - ringframeSize.Y) ringpos1.Y = Window.ClientBounds.Height - ringframeSize.Y; if (ringpos1.X < 0) ringpos1.X = 0; if (ringpos1.X > Window.ClientBounds.Width - ringframeSize.X) ringpos1.X = Window.ClientBounds.Width - ringframeSize.X;
再次編譯運行,現在滑鼠和鍵盤都可以控制三環動畫的移動了,這時動畫始終是停留在視窗之內的!
5:一般性的碰撞檢測
大家知道碰撞檢測是遊戲中非常重要的一個環節,更是涉及到很多數學問題,可是在我們的XNA中,碰撞問題簡化得你都不敢想象,我們首先運行上面的哪一個程式:
這兩個精靈,骷髏頭暫時是固定的,我們可以用鍵盤控制三環精靈,實現碰見檢測可以利用矩形封裝法,也就是用兩個矩形封裝好精靈,然後檢查兩個矩形是否相交,則可判斷是否碰撞,效果如下:
接下來我們需要做的就是檢測兩個矩形在螢幕上是否相交,碰巧XNA為我們提供的矩形類裡面有這樣一個成員函數可以檢測矩形相交,新加一個成員函數,代碼如下:
protected bool colline() //檢測碰撞的代碼 { Rectangle ringRect = new Rectangle((int)ringpos1.X, (int)ringpos1.Y, ringframeSize.X, ringframeSize.Y); Rectangle skullErct = new Rectangle((int)skullpos2.X, (int)skullpos2.Y, skullframeSize.X, skullframeSize.Y); return ringRect.Intersects(skullErct); }
在程式中建立了兩個矩形地區,構造方法中分別給予了兩個精靈的位置,傳回值為布爾類型,利用了矩形類的intersects方法,接下來可以在update方法中檢測碰撞了
if(colline() ).....則執行相關的事情,在這裡我們調用Exit函數,如果碰撞,就馬上終止程式(雖然這不符合邏輯,這裡只是為了示範).
關於碰撞檢測,需要對於矩形的大小和遊戲效率做出權衡,保證在使用者眼睛無法分辨的時候最佳,不可盲目追求碰撞精確性而做過多操作,只會犧牲遊戲效率這是不值得的,
由於本節內容很簡單,到此為止
下一期:使用者自訂精靈類!