martes, 9 de agosto de 2011

XNA – Colisiones 2D, BoundingBox


En el anterior tutorial vimos como dibujar Fuentes en la pantalla, hoy veremos como manejar colisiones en XNA. XNA nos provee de 2 clases para chequear colisiones, BoundingBox y BoundingSphere. En este tutorial veremos el BoundingBox. Que es? El BoundingBox, es una caja imaginaria que abarcara lo que queramos que tenga colisión. Normalmente se utiliza para abarcar texturas que son rectangulares. Para crear un BoundingBox, primero hay que declarar la variable.
BoundingBox bBox;
Luego en el método Update, creamos el BoundingBox.
bbox_1 = new BoundingBox(new Vector3(posicion_1, 0), new Vector3(caja_1.Width + posicion_1.X, caja_1.Height + posicion_1.Y, 0));
Vector3 min: En este parámetro le ponemos la posición de nuestra textura. Vector3 max: Este parámetro sera la posición de nuestra textura mas el ancho y alto de la misma. Con estos dos puntos formara el BoundingBox que rodeara a nuestra textura.
Por eso nosotros lo creamos en el Update, las posiciones siempre estarán cambiando, y el BoundingBox debe seguir a nuestra textura. Cuando detectamos si hay colisión, tenemos dos tipos de deteccion, Contains, Intersect.
if(bbox1.Intersect(bbox2))posicion.X -= 5;
Intersect: Chequea si un BoundingBox toca otro BoundingBox o BoundingSphere.
if(bbox_1.Contains(bbox_2) == ContainmentType.Contains)posicion.X -= 5;
Contains: Chequea si un BoundingBox contiene todo el volumen de otro BoundingBox
Ejemplo Para probar todo lo visto, haremos un pequeño ejemplo. Primero carguen dos texturas de forma rectangular, una mas chica que otra, y una Fuente.
Declaramos las siguientes variables.
Texture2D caja_1;
Vector2 posicion_1;
BoundingBox bbox_1;
 
Texture2D caja_2;
Vector2 posicion_2;
BoundingBox bbox_2;
 
SpriteFont font;
bool intersect;bool contains;
Ahora iniciamos las variables.
protected override void Initialize(){
posicion_1 = new Vector2(100, 100);
posicion_2 = new Vector2(500, 100);
 
base.Initialize();}
 
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
caja_1 = Content.Load< Texture2D >("caja");
caja_2 = Content.Load< Texture2D >("cajachica");
font = Content.Load< SpriteFont >("Font");}
Ahora escribimos el Update de los BoundingBox y el movimiento de la caja grande.
protected override void Update(GameTime gameTime)
{
KeyboardState ks = Keyboard.GetState();
if (ks.IsKeyDown(Keys.Right) == true)posicion_1.X += 3;
if (ks.IsKeyDown(Keys.Left) == true)posicion_1.X -= 3;
if (ks.IsKeyDown(Keys.Down) == true)posicion_1.Y += 3;
if (ks.IsKeyDown(Keys.Up) == true)posicion_1.Y -= 3;
 
bbox_1 = new BoundingBox(new Vector3(posicion_1, 0), new Vector3(caja_1.Width + posicion_1.X,caja_1.Height + posicion_1.Y, 0));
bbox_2 = new BoundingBox(new Vector3(posicion_2, 0), new Vector3(caja_2.Width + posicion_2.X,caja_2.Height + posicion_2.Y, 0));
 
if (bbox_1.Contains(bbox_2) == ContainmentType.Contains)
{
contains = true;
}
else
{
contains = false;
}
 
if (bbox_1.Intersects(bbox_2))
{
intersect = true;
}
else
{
intersect = false;
}
 
base.Update(gameTime);}
Por ultimo, en el Draw.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
 
spriteBatch.Begin();
spriteBatch.Draw(caja_1, posicion_1, Color.White);
spriteBatch.Draw(caja_2, posicion_2, Color.White);
spriteBatch.DrawString(font, "La caja grande contiene a la caja chica =" + contains.ToString(),new Vector2(50, 50), Color.White);spriteBatch.DrawString(font, "La caja grande intersecta con la caja chica=" + intersect.ToString(),new Vector2(50, 75), Color.White);
spriteBatch.End();
 
base.Draw(gameTime);}
Al final, si iniciamos esto, tendríamos una ventana como esta.
Acá terminamos el tutorial de Colisiones 2D sobre BoundingBox, para el próximo veremos BoundingSphere.
Codigo Completo
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;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
 
namespace Mi_Juego_Tutorial_6
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
 
Texture2D caja_1;
Vector2 posicion_1;
BoundingBox bbox_1;
 
Texture2D caja_2;
Vector2 posicion_2;
BoundingBox bbox_2;
 
SpriteFont font;
bool intersect;
bool contains;
 
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
 
protected override void Initialize()
{
posicion_1 = new Vector2(100, 100);
posicion_2 = new Vector2(500, 100);
 
base.Initialize(); }
 
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
caja_1 = Content.Load< Texture2D >("caja");
caja_2 = Content.Load< Texture2D >("cajachica");
font = Content.Load< SpriteFont >("Font");
}
 
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
 
protected override void Update(GameTime gameTime)
{KeyboardState ks = Keyboard.GetState();
if (ks.IsKeyDown(Keys.Right) == true)posicion_1.X += 3;
if (ks.IsKeyDown(Keys.Left) == true)posicion_1.X -= 3;
if (ks.IsKeyDown(Keys.Down) == true)posicion_1.Y += 3;
if (ks.IsKeyDown(Keys.Up) == true)posicion_1.Y -= 3;
 
bbox_1 = new BoundingBox(new Vector3(posicion_1, 0), new Vector3(caja_1.Width + posicion_1.X,caja_1.Height + posicion_1.Y, 0));
bbox_2 = new BoundingBox(new Vector3(posicion_2, 0), new Vector3(caja_2.Width + posicion_2.X,caja_2.Height + posicion_2.Y, 0));
 
if (bbox_1.Contains(bbox_2) == ContainmentType.Contains)
{
contains = true;
}
else{
contains = false;
}
 
if (bbox_1.Intersects(bbox_2))
{
intersect = true;
}
else{
intersect = false;
}
 
base.Update(gameTime);
}
 
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
 
spriteBatch.Begin();
spriteBatch.Draw(caja_1, posicion_1, Color.White);
spriteBatch.Draw(caja_2, posicion_2, Color.White);
spriteBatch.DrawString(font, "La caja grande contiene a la caja chica =" + contains.ToString(),new Vector2(50, 50), Color.White);
spriteBatch.DrawString(font, "La caja grande intersecta con la caja chica=" + intersect.ToString(),new Vector2(50, 75), Color.White);spriteBatch.End();
 
base.Draw(gameTime);}}}