How to use BoundingBox?

Welcome to our first article of "How To Use ...?" Series.I will be writing more than 300 articles for this series.So keep following XNA Section in our community.So lets talk about Bounding Box and How To Use it!



BoundingBox is a structure which defines an axis-aligned box-shaped 3D volume.

The BoundingBox Structure represents the space occupied by a box. The bounding box class is axis aligned. Each face of the bounding box is perpendicular to the x-axis, the y-axis, or the z-axis. 

There are several benefits of using the bounding box for collision detection.
  • The bounding box class fits rectangular shapes aligned with the axis very well. Compared to the bounding sphere class, the bounding box class provides a much tighter fit for non-rotated rectangular objects. 
  • Because the bounding box class is axis aligned, you can make certain assumptions that result in collision checks between bounding boxes being quicker than a bounding box that can be rotated. 
There are a few drawbacks of using the bounding box for collision detection.
  • Rotating a bounding box causes it to no longer be axis aligned. Because of this, if you rotate a model being bounded, you will need to recreate the bounding box. Doing so can be slow, since all the points in an object are iterated through to get the bounding box. If the model has not changed orientation, you can translate the bounding box instead of recreating it. 
  • If the model being bounded is not aligned to the axis, the bounding box will have some empty space. The amount of empty space will be greatest when the object is rotated 45 degrees from an axis. 
  • Empty space in the bounding box can result in false positives when checking for collision. 
1.gif

A sphere-like shape is surrounded by a BoundingBox.BoundingBox is used for Collision Detection processes so in our example i will show you how you can use BoundingBox.

Here is a general Collision Detection code:

void CheckForCollision()
{
  BoundingBox bb1 = new BoundingBox(new Vector3(spritePosition1.X - (sprite1Width / 2), spritePosition1.Y - (sprite1Height / 2), 0), new Vector3(spritePosition1.X + (sprite1Width / 2), spritePosition1.Y + (sprite1Height / 2), 0));
  BoundingBox bb2 = new BoundingBox(new Vector3(spritePosition2.X - (sprite2Width / 2), spritePosition2.Y - (sprite2Height / 2), 0), newVector3(spritePosition2.X + (sprite2Width / 2), spritePosition2.Y + (sprite2Height / 2), 0));
  if (bb1.Intersects(bb2))
  {
   //Do Something if they crash
  }
} 

Ok

We will have 2 ships in our sample game.

2.gif               

As you can see it is about Running-Away from a Pirate ship.

Ok here are the codes.

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 BoundingSample
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D texture1;
        Texture2D texture2;
        Vector2 spritePosition1;
        Vector2 spritePosition2;
        Vector2 spriteSpeed1 = new Vector2(50.0f, 50.0f);
        Vector2 spriteSpeed2 = new Vector2(100.0f, 100.0f);
        int sprite1Height;
        int sprite1Width;
        int sprite2Height;
        int sprite2Width;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
        protected override void Initialize()
        {
            base.Initialize();
        }
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            spriteBatch = new SpriteBatch(GraphicsDevice);
            texture1 = Content.Load<Texture2D>("ship1");
            texture2 = Content.Load<Texture2D>("pirate");
            spritePosition1.X = 0;
            spritePosition1.Y = 0;
            spritePosition2.X = graphics.GraphicsDevice.Viewport.Width - texture1.Width;
            spritePosition2.Y = graphics.GraphicsDevice.Viewport.Height - texture1.Height;
            sprite1Height = texture1.Height;
            sprite1Width = texture1.Width;
            sprite2Height = texture2.Height;
            sprite2Width = texture2.Width;
        }
        protected override void UnloadContent()
        {
        }
        protected override void Update(GameTime gameTime)
        {
            UpdateSprite(gameTime, ref spritePosition1, ref spriteSpeed1);
            UpdateSprite(gameTime, ref spritePosition2, ref spriteSpeed2);
            CheckForCollision();
            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
            spriteBatch.Draw(texture1, spritePosition1, Color.White);
            spriteBatch.End();
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
            spriteBatch.Draw(texture2, spritePosition2, Color.Gray);
            spriteBatch.End();
            base.Draw(gameTime);
        }
        void UpdateSprite(GameTime gameTime, ref Vector2 spritePosition, ref Vector2 spriteSpeed)
        {
            spritePosition +=
                spriteSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            int MaxX =
                graphics.GraphicsDevice.Viewport.Width - texture1.Width;
            int MinX = 0;
            int MaxY =
                graphics.GraphicsDevice.Viewport.Height - texture1.Height;
            int MinY = 0;
            if (spritePosition.X > MaxX)
            {
                spriteSpeed.X *= -1;
                spritePosition.X = MaxX;
            }
            else if (spritePosition.X < MinX)
            {
                spriteSpeed.X *= -1;
                spritePosition.X = MinX;
            }
            if (spritePosition.Y > MaxY)
            {
                spriteSpeed.Y *= -1;
                spritePosition.Y = MaxY;
            }
            else if (spritePosition.Y < MinY)
            {
                spriteSpeed.Y *= -1;
                spritePosition.Y = MinY;
            }
        }
        void CheckForCollision()
        {
            BoundingBox bb1 = new BoundingBox(new Vector3(spritePosition1.X - (sprite1Width / 2), spritePosition1.Y - (sprite1Height / 2), 0), new Vector3(spritePosition1.X + (sprite1Width / 2), spritePosition1.Y + (sprite1Height / 2), 0));
            BoundingBox bb2 = new BoundingBox(new Vector3(spritePosition2.X - (sprite2Width / 2), spritePosition2.Y - (sprite2Height / 2), 0), new Vector3(spritePosition2.X + (sprite2Width / 2), spritePosition2.Y + (sprite2Height / 2), 0));
            if (bb1.Intersects(bb2))
            {
                Window.Title = "OH NO PIRATES AGAIN! SOMEBODY HELP US!!!";
                spritePosition1.X = 0;
                spritePosition1.Y = 0;
                spritePosition2.X = graphics.GraphicsDevice.Viewport.Width - texture1.Width;
                spritePosition2.Y = graphics.GraphicsDevice.Viewport.Height - texture1.Height;
            }
        }
    }
}

We are using two textures and in CheckForCollision method we are surrounding the sprites with BoundingBoxes where we can know if Collision Detection has happened.

In UpdateSprite method we are checking whether the sprites crashing into Viewport's borders (which is windows borders).

When you run the project you will see something like that.

3.gif

Nice isnt it!

In this article I have talked about what BoundingBox was and how its being used.And I hope you now have less to fear from it :)