XNA4.0学习笔记2:控制精灵和碰撞检测

来源:互联网 发布:java 根据域名获取ip 编辑:程序博客网 时间:2024/06/14 08:56

                                           精灵的控制和碰撞检测


        上一节我们了解了精灵的绘制,移动以及动画的实现,并且在最后我们实现了三个环的简单动画,今天我们学习下如何通过设备控制精灵,这一节的内容比较简单,很好理解,在这里我先把控制精灵的全部代码贴上来,方便接下来的学习!

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函数,如果碰撞,就马上终止程序(虽然这不符合逻辑,这里只是为了演示).


关于碰撞检测,需要对于矩形的大小和游戏效率做出权衡,保证在用户眼睛无法分辨的时候最佳,不可盲目追求碰撞精确性而做过多操作,只会牺牲游戏效率这是不值得的,

由于本节内容很简单,到此为止


下一期:用户自定义精灵类!





原创粉丝点击