Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I can easily rotate my sprite, but how could I rotate my rectangle for my collision (Thinking of using the Separating Axis Theorem, But I have no clue how to apply it) Help or Example would be appreciated :)

Game1 Class:

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 CombatTank
{

public class Game1 : Microsoft.Xna.Framework.Game
{
    //Declare Graphic Manager & Spritebatch
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    //Declare Player 1
    theBody player1TankBody;

    //Declare Player 2
    theBody player2TankBody;

    //Save Player 1 Position
    Vector2 savedPlayer1TankBodyPosition;

    //Save Player 2 Position
    Vector2 savedPlayer2TankBodyPosition;

    //Declare Keyboard States
    KeyboardState currentkeyboardState;
    KeyboardState previousKeyboardState;


    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    protected override void Initialize()
    {
        //TankBody Position Player 1
        Vector2 player1TankBodyPosition = new Vector2(200, 200);
        Vector2 player2TankBodyPosition = new Vector2(400, 200);

        //TankBody Scale 
        float player1TankBodyScale = 1.0F;
        float player2TankBodyScale = 1.0F;

        //TankBody Rotation
        float player1TankBodyRotation = 0.0F;
        float player2TankBodyRotation = 0.0F;

        //TankBody Color
        Color player1TankBodyColor = Color.Red;
        Color player2TankBodyColor = Color.Blue;

        //Create Tank
        player1TankBody = new theBody(player1TankBodyPosition,player1TankBodyScale, player1TankBodyRotation, player1TankBodyColor);
        player2TankBody = new theBody(player2TankBodyPosition, player2TankBodyScale, player2TankBodyRotation, player2TankBodyColor);

        base.Initialize();
    }

    protected override void LoadContent()
    {
        //Create New SpriteBatch
        spriteBatch = new SpriteBatch(GraphicsDevice);

        //Load The Player 1 TankBody Texture
        Texture2D player1SpriteTankBody = Content.Load<Texture2D>("TankBody");
        player1TankBody.LoadContent(Content,"TankBody");

        //Extract Collision Data For Player 1
        player1TankBody.TankBodyTextureData = new Color[player1TankBody.Texture.Width * player1TankBody.Texture.Height];
        player1TankBody.Texture.GetData(player1TankBody.TankBodyTextureData);

        //Load The Player 2 TankBody Texture
        Texture2D player2SpriteTankBody = Content.Load<Texture2D>("TankBody");
        player2TankBody.LoadContent(Content, "TankBody");

        //Extract Collision Data For Player 2
        player2TankBody.TankBodyTextureData = new Color[player2TankBody.Texture.Width * player2TankBody.Texture.Height];
        player2TankBody.Texture.GetData(player2TankBody.TankBodyTextureData);

    }

    protected override void UnloadContent()
    {

    }


    protected override void Update(GameTime gameTime)
    {
        //Save Player 1 Postion
        savedPlayer1TankBodyPosition.X = player1TankBody.Position.X;
        savedPlayer1TankBodyPosition.Y = player1TankBody.Position.Y;

        //Save Player 2 Position
        savedPlayer2TankBodyPosition.X = player2TankBody.Position.X;
        savedPlayer2TankBodyPosition.Y = player2TankBody.Position.Y;

        //Updates Player 1
        UpdatePlayer1(gameTime);

        //Update Player 2
        UpdatePlayer2(gameTime);

        //Collision Player 1
        CollisionPlayer1(gameTime);

        //Collision Player 2
        CollisionPlayer2(gameTime);

        base.Update(gameTime);
    }

    private void UpdatePlayer1(GameTime gameTime)
    {
        //Save the previous state of the keyboard
        previousKeyboardState = currentkeyboardState;

        //Read the current state of the keyboard
        currentkeyboardState = Keyboard.GetState();

        //TankBody Movement
        if (currentkeyboardState.IsKeyDown(Keys.W))
        {
            //Move Tank Forward
            player1TankBody.Position.X -= 5 * (float)Math.Cos(player1TankBody.Rotation);
            player1TankBody.Position.Y -= 5 * (float)Math.Sin(player1TankBody.Rotation);
        }
        if (currentkeyboardState.IsKeyDown(Keys.S))
        {
            //Move Tank Backwards
            player1TankBody.Position.X += 5 * (float)Math.Cos(player1TankBody.Rotation);
            player1TankBody.Position.Y += 5 * (float)Math.Sin(player1TankBody.Rotation);

        }
        if (currentkeyboardState.IsKeyDown(Keys.A))
        {
            player1TankBody.Rotation -= 0.03f;
        }
        if (currentkeyboardState.IsKeyDown(Keys.D))
        {
            player1TankBody.Rotation += 0.03f;
        }

    }

    private void UpdatePlayer2(GameTime gameTime)
    {
        //Save the previous state of the keyboard
        previousKeyboardState = currentkeyboardState;

        //Read the current state of the keyboard
        currentkeyboardState = Keyboard.GetState();

        //TankBody Movement
        if (currentkeyboardState.IsKeyDown(Keys.Up))
        {
            //Move Tank Forward
            player2TankBody.Position.X -= 5 * (float)Math.Cos(player2TankBody.Rotation);
            player2TankBody.Position.Y -= 5 * (float)Math.Sin(player2TankBody.Rotation);
        }
        if (currentkeyboardState.IsKeyDown(Keys.Down))
        {
            //Move Tank Backward
            player2TankBody.Position.X += 5 * (float)Math.Cos(player2TankBody.Rotation);
            player2TankBody.Position.Y += 5 * (float)Math.Sin(player2TankBody.Rotation);
        }
        if (currentkeyboardState.IsKeyDown(Keys.Left))
        {
            player2TankBody.Rotation -= 0.03f;
        }
        if (currentkeyboardState.IsKeyDown(Keys.Right))
        {
            player2TankBody.Rotation += 0.03f;
        }

    }

    private void CollisionPlayer1(GameTime gameTime)
    {


        if (IntersectPixels(player1TankBody.BoundingBox, player1TankBody.TankBodyTextureData, player2TankBody.BoundingBox, player2TankBody.TankBodyTextureData))
        {
            player1TankBody.Position.X = savedPlayer1TankBodyPosition.X;
            player1TankBody.Position.Y = savedPlayer1TankBodyPosition.Y;

        }



    }

    private void CollisionPlayer2(GameTime gameTime)
    {
        if (IntersectPixels(player2TankBody.BoundingBox, player2TankBody.TankBodyTextureData, player1TankBody.BoundingBox, player1TankBody.TankBodyTextureData))
        {
            player2TankBody.Position.X = savedPlayer2TankBodyPosition.X;
            player2TankBody.Position.Y = savedPlayer2TankBodyPosition.Y;

        }
    }


    static bool IntersectPixels(Rectangle rectangleA, Color[] dataA, Rectangle rectangleB, Color[] dataB)
    {
        //Find top Bound of the Rectangle
        int top = Math.Max(rectangleA.Top, rectangleB.Top);
        int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
        int left = Math.Max(rectangleA.Left, rectangleB.Left);
        int right = Math.Min(rectangleA.Right, rectangleB.Right);

        for (int y = top; y < bottom; y++)
        {
            for (int x = left; x < right; x++)
            {
                //Get Color of both Pixels
                Color colorA = dataA[(x - rectangleA.Left) + (y - rectangleA.Top) * rectangleA.Width];
                Color colorB = dataB[(x - rectangleB.Left) + (y - rectangleB.Top) * rectangleB.Width];

                //Both pixel are not completely Transparent
                if (colorA.A != 0 && colorB.B != 0)
                {
                    //Then an intersection is found 
                    return true;
                }

            }

        }


        //No Intersection
        return false;
    }





    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);

        spriteBatch.Begin();

        player1TankBody.Draw(spriteBatch);
        player2TankBody.Draw(spriteBatch);

        spriteBatch.End();

        base.Draw(gameTime);
    }
}
}

theBody Class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;

namespace CombatTank
{
class theBody
{
    //TankBody Texture
    private Texture2D texture;
    public Texture2D Texture
    {
        get
        { 
            return texture; 
        }
    }

    //TankBody Height
    private float height;
    public float Height
    {
        get
        {
            return height;
        }
    }

    //TankBody Width
    private float width;
    private float Width
    {
        get
        {
            return width;
        }

    }

    //TankBody Position
    public Vector2 Position;

    //TankBody Origin
    public Vector2 Origin;

    //TankBody Rotation
    public float Rotation = 0.0F;

    //TankBody Color
    public Color Color = Color.White;

    //TankBody Scale
    public float Scale = 1F;

    //TankBody BoundingBox
    public Rectangle BoundingBox
    {
        get
        {
            return new Rectangle((int)Position.X, (int)Position.Y, (int)texture.Width, (int)texture.Height);
        }
    }

    //TankBody color Data(Used For Pixel Collision)
    public Color[] TankBodyTextureData;

    //TankBody Constructor
    public theBody(Vector2 position,float scale,float rotation, Color color)
    {
        Position = position;
        Scale = scale;
        Rotation = rotation;
        Color = color;
    }

    //LoadContent
    public void LoadContent(ContentManager contentManager, string assetname)
    {
        texture = contentManager.Load<Texture2D>(assetname);
        Origin = new Vector2(Texture.Width / 2, Texture.Height / 2);
    }

    //Draw
    public virtual void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(texture, Position, null, Color, Rotation, Origin, Scale, SpriteEffects.None, 0);
    }

    //Update
    public void Update(GameTime gameTime)
    {

    }
}
}
share|improve this question
    
You really should limit your code to just what's relevant to the problem at hand. You should also call out explicitly what you've tried, and what you're specifically having problems with. –  Tetrad May 10 '12 at 16:31
add comment

2 Answers

up vote 0 down vote accepted

SAT method of collision can be hard to implement if you don't know what is being accomplished when implementing it. This blog post helped me but I found many more explanations and examples on the internet to supplement myself. Being able to "apply" something and "control" something make all the difference when making fun games. I recommend that you take the time to understand the math before you attempt to implement it.

http://www.codezealot.org/archives/55

share|improve this answer
add comment

First of all, you should perform a distance-based pruning of possible collisions. A bounding rectangle around object O1 with a longer edge of length a has a potential collision radius R1 = sqrt(2) * a/2, so if another object O2 with collision radius R2 is more than R1+R2 apart, they cannot collide. Only if the collision circles intersect should you check for the more complicated rectangle collision. Work with squared values to avoid the expensive sqrt(), except if you need the actual distance anyway.

Then you need to change your BoundingBox property and collision detection method to support arbitrarily rotated rectangles. Instead of the Rectangle class, use 4 Points named UpperLeft, UpperRight, LowerLeft, LowerRight that you adjust according to the object's rotation. Then you use, as you already noted, the Separating Axis Theorem. Since you are using Rectangles, you can use a lot of optimizations. Details here, including Maths:

2D Rotated Rectangle Collision

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.