程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 控制精靈和碰撞檢測

控制精靈和碰撞檢測

編輯:C#入門知識

[csharp] 
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); 
        } 
    } 

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方法中實現移動的距離更新,代碼如下:


[csharp] 
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; 

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 方法的調用之前:

 

[csharp]
MouseState mouseState = Mouse.GetState();                               //鼠標控制三環動畫語句  
            if (mouseState.X != prevmousestate.X || mouseState.Y != prevmousestate.Y)  
                ringpos1 = new Vector2(mouseState.X, mouseState.Y);  
            prevmousestate = mouseState; 

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 方法的調用之前:

 

[csharp] 
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; 

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為我們提供的矩形類裡面有這樣一個成員函數可以檢測矩形相交,新加一個成員函數,代碼如下:

 

 

[csharp] 
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); 
        } 

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函數,如果碰撞,就馬上終止程序(雖然這不符合邏輯,這裡只是為了演示).

 


關於碰撞檢測,需要對於矩形的大小和游戲效率做出權衡,保證在用戶眼睛無法分辨的時候最佳,不可盲目追求碰撞精確性而做過多操作,只會犧牲游戲效率這是不值得的,

由於本節內容很簡單,到此為止

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved