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


                                               精灵的控制和碰撞检测


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

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


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

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


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





  • 相关阅读:
    我来教你用AWS IoT.Part1--配置和接入
    Netty进行文件传输
    Spring Security-利用URL地址进行权限控制
    Java开发工作中常见问题
    java进阶学习计划
    spring cloud常用注解及关键类
    系统设计-电商排名
    java实现十大经典算法
    JDK8如何写出优雅代码
    Java实现迷宫和八皇后
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3003753.html
Copyright © 2020-2023  润新知