梦想成真 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
[源码下载]