Ioannis Panagopoulos blog

Tutorials on HTML5, Javascript, WinRT and .NET

XNA 2D Basic Collision Detection with Rotation (Scene2Sprite)

by Ioannis Panagopoulos

In the previous post we have worked with collision detection between roated sprites. In this post we will deal with the situtation where we want to detect whether a specific sprite that can be rotated is in a specific area in the scene (eg a car is on the road in the scene).

Suppose that you have the following scenario:

 

A car is driven by the user around the scene. When the car hits the boundaries of the road, the car should lose all of its speed. The user uses the UP/DOWN keys to acelerate/break and LEFT/RIGHT for steering.

You want to detect the situation where the car is going out of the road bounds. A way to do this is as follows:

Use a second texture of the road, one that you will use for collision detection which has a specific plain color for the road:

Then get the bounding rectangle of the rotated texture that is parallel to the window's axis:

Within this rectangle check whether there is one point that is on the car's texture but the equivalent point on the road texture is not gray.

This programmatically is achieved as follows:

To get a rotated texture alone from scene, you use an additional back-buffer where you draw the rotated car's texture and then get a snapshot of it. The AdditionalRenderTargetForCollision is initialized once in the main game loop (download the project to see how):

public static RenderTarget2D AdditionalRenderTargetForCollision { get; set; }

private static Color[] _getSingleSpriteAloneFromScene(SpriteBatch spriteBatch,Texture2D textureToDraw,
                             Vector2 Position,Vector2 Origin,float Theta,List<Vector2> RectanglePoints)
{
    spriteBatch.GraphicsDevice.SetRenderTarget(0, AdditionalRenderTargetForCollision);
    spriteBatch.GraphicsDevice.Clear(Color.Black);
    spriteBatch.Begin();
    spriteBatch.Draw(textureToDraw, Position, null, Color.White, 
                                     Theta, Origin, 1.0f, SpriteEffects.None, 0);
    spriteBatch.End();
    spriteBatch.GraphicsDevice.SetRenderTarget(0, null);
    Texture2D SceneTexture = AdditionalRenderTargetForCollision.GetTexture();
    Rectangle BoundingRectangle = _getBoundingRectangleOfRotatedRectangle(RectanglePoints);
    int PixelSize = BoundingRectangle.Width * BoundingRectangle.Height;
    Color[] TextureData = new Color[PixelSize];
    SceneTexture.GetData(0, BoundingRectangle, TextureData, 0, PixelSize);

    return TextureData;
}

The code that checks for bounds is as follows:

public static bool SpriteIsOnValidArea(Texture2D TextureScene, Texture2D TextureSprite, Vector2 PosSprite, Vector2 OrigSprite, List<Vector2> RectSprite,float ThetaSprite,SpriteBatch spriteBatch,Color OKColor)
 {
     Color[] TextureDataSprite = _getSingleSpriteAloneFromScene(spriteBatch, TextureSprite, PosSprite, OrigSprite, ThetaSprite, RectSprite);
     Color[] TextureDataScene =  new Color[TextureScene.Width*TextureScene.Height];
     TextureScene.GetData(TextureDataScene);


     Rectangle RectangleSpriteBounding = _getBoundingRectangleOfRotatedRectangle(RectSprite);
     for (int i = RectangleSpriteBounding.Top; i < RectangleSpriteBounding.Bottom; i++)
         for (int j = RectangleSpriteBounding.Left; j < RectangleSpriteBounding.Right; j++)
             if (TextureDataScene[i * TextureScene.Width + j] != OKColor && TextureDataSprite[(i-RectangleSpriteBounding.Top) *
                 RectangleSpriteBounding.Width + (j-RectangleSpriteBounding.Left)] != new Color(0,0,0,0))
                 return false;
    
     return true;
 }

 

The code initially gets the car's rotated texture and the scene's texture. It then uses a method to calculate the bounding rectangle of the rotated sprite's texture. Then, within this rectangle it tests for the sprite's pixels one by one. If it locates even one texture's point that is not on the selected color (OKColor) it returns false (the car is out of bounds).

The project that performs this kind of collision detection can be downloaded here.

 (You may also want to check out a newer post on integrating a Physics Engine with XNA here)

kick it on DotNetKicks.com

Shout it

blog comments powered by Disqus
hire me