您的位置:首页 > 其它

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

2011-08-15 10:07 423 查看
[索引页]
[源码下载]

[align=center]梦想成真 XNA (7) - 碰撞检测[/align]

作者: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
[源码下载]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: