• 梦想成真 XNA (7) 碰撞检测


    [索引页]
    [源码下载] 


    梦想成真 XNA (7) - 碰撞检测



    作者:webabcd


    介绍
    XNA: 碰撞检测

    • 通过 AABB(Axis Aligned Bounding Box)实现碰撞检测算法
    • 通过 Rectangle 类实现碰撞检测算法



    示例
    1、AABB 算法的 Demo(按键盘 N 键加载此 Demo)
    Component/Collision/AABB.cs

    /*
     * AABB - Axis Aligned Bounding Box
     * 所谓的坐标轴对齐(Axis Aligned),指的是盒体与世界坐标轴平行,同时盒体的每个边(2D)或面(3D)都和一条坐标轴平行(垂直)
     * 
     * 本 Demo 用于演示通过 AABB 算法检测两个精灵是否发生了碰撞
     */
    
    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 XNA.Component.Collision
    {
        public class AABB : Microsoft.Xna.Framework.DrawableGameComponent
        {
            // 精灵绘制器
            SpriteBatch _spriteBatch;
    
            // 精灵对象
            Texture2D _sprite;
    
            // 精灵的位置(系统控制的)
            Vector2 _systemSpritePosition = new Vector2(600, 300);
    
            // 精灵的速度(系统控制的),单位:像素数/每帧
            int _systemSpriteSpeed = 6;
    
            // 精灵的位置(用户控制的)
            Vector2 _userSpritePosition = Vector2.Zero;
    
            // 精灵的速度(用户控制的),单位:像素数/每帧
            int _userSpriteSpeed = 6;
    
            // 是否发生了碰撞
            bool _collided = false;
    
            public AABB(Game game)
                : base(game)
            {
    
            }
    
            public override void Initialize()
            {
                base.Initialize();
            }
    
            protected override void LoadContent()
            {
                _spriteBatch = new SpriteBatch(Game.GraphicsDevice);
                _sprite = Game.Content.Load<Texture2D>("Image/Son");
            }
    
            public override void Update(GameTime gameTime)
            {
                // 如果系统控制的精灵和用户控制的精灵发生了碰撞,则停止动画
                if (!CheckCollision())
                {
                    calcSystemSpritePosition();
                    calcUserSpritePosition();
                }
                else
                {
                    _collided = true;
                }
    
                base.Update(gameTime);
            }
    
            /// <summary>
            /// 检查系统控制的精灵和用户控制的精灵是否发生了碰撞(通过 AABB 算法)
            /// </summary>
            /// <returns>两个精灵是否发生了碰撞</returns>
            private bool CheckCollision()
            {
                /*
                 * 盒体与世界坐标轴平行,同时盒体的每个边(2D)或面(3D)都和一条坐标轴平行
                 * AABB 包围盒是由一个 Max 坐标和一个 Min 坐标组成的,算法如下
                 */
    
                Vector2 systemSpriteMin = new Vector2(_systemSpritePosition.X, _systemSpritePosition.Y);
                Vector2 systemSpriteMax = new Vector2(_systemSpritePosition.X + _sprite.Width, _systemSpritePosition.Y + _sprite.Height);
                Vector2 userSpriteMin = new Vector2(_userSpritePosition.X, _userSpritePosition.Y);
                Vector2 userSpriteMax = new Vector2(_userSpritePosition.X + _sprite.Width, _userSpritePosition.Y + _sprite.Height);
    
                if (systemSpriteMin.X <= userSpriteMax.X && systemSpriteMin.Y <= userSpriteMax.Y && systemSpriteMax.X >= userSpriteMin.X && systemSpriteMax.Y >= userSpriteMin.Y)
                    return true;
    
                return false;
            }
    
            // 计算用户控制的精灵的位置
            private void calcUserSpritePosition()
            {
                KeyboardState keyboardState = Keyboard.GetState();
    
                if (keyboardState.IsKeyDown(Keys.Left) && _userSpritePosition.X >= 0)
                    _userSpritePosition.X -= _userSpriteSpeed;
                if (keyboardState.IsKeyDown(Keys.Right) && _userSpritePosition.X <= Game.Window.ClientBounds.Width - _sprite.Width)
                    _userSpritePosition.X += _userSpriteSpeed;
                if (keyboardState.IsKeyDown(Keys.Up) && _userSpritePosition.Y >= 0)
                    _userSpritePosition.Y -= _userSpriteSpeed;
                if (keyboardState.IsKeyDown(Keys.Down) && _userSpritePosition.Y <= Game.Window.ClientBounds.Height - _sprite.Height)
                    _userSpritePosition.Y += _userSpriteSpeed;
    
            }
    
            // 计算系统控制的精灵的位置
            private void calcSystemSpritePosition()
            {
                // 系统控制的精灵在 Y 轴方向上做往复运动
                _systemSpritePosition.Y += _systemSpriteSpeed;
    
                if (_systemSpritePosition.Y > Game.Window.ClientBounds.Height - _sprite.Height || _systemSpritePosition.Y < 0)
                    _systemSpriteSpeed *= -1;
            }
    
            public override void Draw(GameTime gameTime)
            {
                if (_collided)
                    Game.GraphicsDevice.Clear(Color.IndianRed);
                else
                    Game.GraphicsDevice.Clear(Color.CornflowerBlue);
    
                // 在指定的位置上绘制精灵
                _spriteBatch.Begin();
                _spriteBatch.Draw(_sprite, _systemSpritePosition, Color.Red); // 绘制系统控制的精灵
                _spriteBatch.Draw(_sprite, _userSpritePosition, Color.White); // 绘制用户控制的精灵
                _spriteBatch.End();
    
                base.Update(gameTime);
            }
        }
    }
    



    2、通过 Rectangle 检测碰撞的 Demo(按键盘 O 键加载此 Demo)
    Component/Collision/RectangleCollision.cs 

    /*
     * 本 Demo 用于演示通过 Rectangle 类实现碰撞检测算法
     */
    
    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 XNA.Component.Collision
    {
        public class RectangleCollision : Microsoft.Xna.Framework.DrawableGameComponent
        {
            // 精灵绘制器
            SpriteBatch _spriteBatch;
    
            // 精灵对象
            Texture2D _sprite;
    
            // 精灵的位置(系统控制的)
            Vector2 _systemSpritePosition = new Vector2(600, 300);
    
            // 精灵的速度(系统控制的),单位:像素数/每帧
            int _systemSpriteSpeed = 6;
    
            // 精灵的位置(用户控制的)
            Vector2 _userSpritePosition = Vector2.Zero;
    
            // 精灵的速度(用户控制的),单位:像素数/每帧
            int _userSpriteSpeed = 6;
    
            // 是否发生了碰撞
            bool _collided = false;
    
            public RectangleCollision(Game game)
                : base(game)
            {
    
            }
    
            public override void Initialize()
            {
                base.Initialize();
            }
    
            protected override void LoadContent()
            {
                _spriteBatch = new SpriteBatch(Game.GraphicsDevice);
                _sprite = Game.Content.Load<Texture2D>("Image/Son");
            }
    
            public override void Update(GameTime gameTime)
            {
                // 如果系统控制的精灵和用户控制的精灵发生了碰撞,则停止动画
                if (!CheckCollision())
                {
                    calcSystemSpritePosition();
                    calcUserSpritePosition();
                }
                else
                {
                    _collided = true;
                }
    
                base.Update(gameTime);
            }
    
            /// <summary>
            /// 检查系统控制的精灵和用户控制的精灵是否发生了碰撞(通过 Rectangle 类的帮助)
            /// </summary>
            /// <returns>两个精灵是否发生了碰撞</returns>
            private bool CheckCollision()
            {
                Rectangle systemSpriteRect = new Rectangle((int)_systemSpritePosition.X, (int)_systemSpritePosition.Y, _sprite.Width, _sprite.Height);
                Rectangle userSpriteRect = new Rectangle((int)_userSpritePosition.X, (int)_userSpritePosition.Y, _sprite.Width, _sprite.Height);
    
                if (systemSpriteRect.Intersects(userSpriteRect))
                    return true;
    
                return false;
            }
    
            // 计算用户控制的精灵的位置
            private void calcUserSpritePosition()
            {
                KeyboardState keyboardState = Keyboard.GetState();
    
                if (keyboardState.IsKeyDown(Keys.Left) && _userSpritePosition.X >= 0)
                    _userSpritePosition.X -= _userSpriteSpeed;
                if (keyboardState.IsKeyDown(Keys.Right) && _userSpritePosition.X <= Game.Window.ClientBounds.Width - _sprite.Width)
                    _userSpritePosition.X += _userSpriteSpeed;
                if (keyboardState.IsKeyDown(Keys.Up) && _userSpritePosition.Y >= 0)
                    _userSpritePosition.Y -= _userSpriteSpeed;
                if (keyboardState.IsKeyDown(Keys.Down) && _userSpritePosition.Y <= Game.Window.ClientBounds.Height - _sprite.Height)
                    _userSpritePosition.Y += _userSpriteSpeed;
    
            }
    
            // 计算系统控制的精灵的位置
            private void calcSystemSpritePosition()
            {
                // 系统控制的精灵在 Y 轴方向上做往复运动
                _systemSpritePosition.Y += _systemSpriteSpeed;
    
                if (_systemSpritePosition.Y > Game.Window.ClientBounds.Height - _sprite.Height || _systemSpritePosition.Y < 0)
                    _systemSpriteSpeed *= -1;
            }
    
            public override void Draw(GameTime gameTime)
            {
                if (_collided)
                    Game.GraphicsDevice.Clear(Color.IndianRed);
                else
                    Game.GraphicsDevice.Clear(Color.CornflowerBlue);
    
                // 在指定的位置上绘制精灵
                _spriteBatch.Begin();
                _spriteBatch.Draw(_sprite, _systemSpritePosition, Color.Red); // 绘制系统控制的精灵
                _spriteBatch.Draw(_sprite, _userSpritePosition, Color.White); // 绘制用户控制的精灵
                _spriteBatch.End();
    
                base.Update(gameTime);
            }
        }
    }
    



    OK 
    [源码下载]

  • 相关阅读:
    Unity3d修炼之路:游戏开发中,3d数学知识的练习【1】(不断更新.......)
    Codeforces 463C Gargari and Bishops 题解
    kettle入门(七) 之kettle增量方案(一)全量比对取增量-依据唯一标示
    cpp学习笔记 1一个简单的小程序以及一些的知识点
    POJ 1321-棋盘问题(DFS)
    偶遇 smon 进程cpu 开销高异常分析
    Android 虚线切割线
    magento安装wordpress
    分组password算法
    Android_编程规范与经常使用技巧
  • 原文地址:https://www.cnblogs.com/webabcd/p/2138732.html
Copyright © 2020-2023  润新知