1
\$\begingroup\$

So in my most recent 2D game I draw objects like so.

_spriteBatch.Draw(_sprite, Center(), null, Color.White, _rotation, new Vector2(_sprite.Width / 2, _sprite.Height / 2), _scale, SpriteEffects.None, 0);

My bounding boxes are generated using a two step algorithm where I make the transform matrix, then apply it to a Rectangle of the sprite's height and width.

    public Rectangle BoundingBoxTransformed
    {
        get
        {
            //Center and rotate our Rectangle

            Matrix m = Matrix.CreateScale(_scale) * 
                Matrix.CreateTranslation(new Vector3(new Vector2((float)-BoundingBox.Width / 2, (float)-BoundingBox.Height / 2), 0.0f)) *
                Matrix.CreateRotationZ(_rotation) *
            //Move our rectangle toward the player, then recenter it by undoing the original translation (now that it's already rotated)

                Matrix.CreateTranslation(new Vector3(_location, 0.0f)) * Matrix.CreateTranslation(new Vector3((float)BoundingBox.Width / 2, (float)BoundingBox.Height / 2, 0.0f));
            return CalculateBoundingRectangle(new Rectangle(0, 0, _sprite.Width, _sprite.Height), m);
        }
    }

This is how I've been finding the new sizes for the scaled bounding boxes.

   public static Rectangle CalculateBoundingRectangle(Rectangle rectangle,
                                                       Matrix transform)
    {
        // Get all four corners in local space
        Vector2 leftTop = new Vector2(rectangle.Left, rectangle.Top);
        Vector2 rightTop = new Vector2(rectangle.Right, rectangle.Top);
        Vector2 leftBottom = new Vector2(rectangle.Left, rectangle.Bottom);
        Vector2 rightBottom = new Vector2(rectangle.Right, rectangle.Bottom);
        // Transform all four corners into work space
        Vector2.Transform(ref leftTop, ref transform, out leftTop);
        Vector2.Transform(ref rightTop, ref transform, out rightTop);
        Vector2.Transform(ref leftBottom, ref transform, out leftBottom);
        Vector2.Transform(ref rightBottom, ref transform, out rightBottom);
        // Find the minimum and maximum extents of the rectangle in world space
        Vector2 min = Vector2.Min(Vector2.Min(leftTop, rightTop),
                                  Vector2.Min(leftBottom, rightBottom));
        Vector2 max = Vector2.Max(Vector2.Max(leftTop, rightTop),
                                  Vector2.Max(leftBottom, rightBottom));
        // Return that as a rectangle
        return new Rectangle((int)min.X, (int)min.Y,
                             (int)(max.X - min.X), (int)(max.Y - min.Y));
    }

I thought that I had the transformations all figured out, but when I run the game, I can see that my bounding boxes do not match up with my sprites.

Note the area marked in orange, where the sprite exits the box, and the area above it, where the box is empty, suggesting one or the other is misaligned

enter image description here

So what is it that's going on here? Are my transformations out of order? Quick edit: The purple boxes are the original bounding boxes, which are used to determine the height and width of the red (transformed, i.e. scaled and rotated) bounding boxes.

\$\endgroup\$
2
  • \$\begingroup\$ What is _rotation? You should confirm it with a break point while debugging. \$\endgroup\$ Commented Jun 18, 2013 at 3:41
  • \$\begingroup\$ @SethBattin I've added a picture to the question showing the rotations of various rotated/unrotated sprites. The bug exists at all angles, but rotation seems to be working as expected. \$\endgroup\$
    – SomeGuy
    Commented Jun 18, 2013 at 4:38

1 Answer 1

2
\$\begingroup\$

I think this may be your problem:

Matrix.CreateTranslation(new Vector3(new Vector2((float)-BoundingBox.Width / 2, (float)-BoundingBox.Height / 2), 0.0f))

It appears you are trying to create a translation to the point of origin, which is what you should do when creating a rotation matrix, however, you are creating it based on your BoundingBox width and height. This should be your sprites original width and height.

Instead try:

Vector2 origin = new Vector2(_location.X + _sprite.Width / 2, _location.Y + _sprite.Height / 2);

Matrix m = Matrix.CreateTranslation(new Vector3(-origin), 0.0f)) *  
    Matrix.CreateScale(_scale) * 
    Matrix.CreateRotationZ(_rotation) *
    Matrix.CreateTranslation(new Vector3(_location, 0.0f)) * 
    Matrix.CreateTranslation(new Vector3(origin, 0.0f));

And then in your draw code:

_spriteBatch.Draw(_sprite, _location, null, Color.White, _rotation, origin, _scale, SpriteEffects.None, 0);
\$\endgroup\$
3
  • \$\begingroup\$ No luck with chaging the code there, though I've done it anyways since it's cleaner this way. I feel like if it were an issue with the scaling matrix, the rectangle would come out too large/small, rather than off-center, but I'm not really sure how matrices work. \$\endgroup\$
    – SomeGuy
    Commented Jun 18, 2013 at 16:30
  • \$\begingroup\$ @SomeGuy To me it looks like you have the right dimensions, it just seems like you have a Translation that is slightly off. Almost seems like the point of origin is off by a few pixels or something. \$\endgroup\$
    – jgallant
    Commented Jun 18, 2013 at 16:46
  • \$\begingroup\$ whoops, I mixed you up with a discussion I was having on steam about scaling matrices, sorry about that. Your code was giving me some issues at first due to the way I was drawing sprites originally (I was drawing from the center, which was throwing the origin off a little). Having updated the code, it works beautifully, save that the boxes are sometimes a pixel or two too small due to rounding errors. Nice catch! \$\endgroup\$
    – SomeGuy
    Commented Jun 18, 2013 at 16:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .