Why rotate a sprite is simple and rotate a rectangle is damn complex ?

All is in the title but for more info :

If you want to rotate a sprite, it’s easy, you use the method :
SpriteBatch.Draw (Texture2D, Vector2, Nullable, Color, Single, Vector2, Single, SpriteEffects, Single)
Here single accept a radian to apply a rotation.
That’s neat.

And on the over hand, if you want to rotate a Rectangle, you have to use the Transfrom() method (that i don’t totally understand because documentation about this is bad) you will need to create every corner of the Rectangle you want to rotate and manage them. I guess this can add huge work depending on what you want to achieve.

For my game, i would like to apply rotation in my Update() instead of my draw to detect specific collision between rectangles with my logic code.

I tried to use :

`vector2_of_my_rect = new Vector2(100, 100);
my_rect = new Rectangle(vector2_of_my_rect.X, vector2_of_my_rect.Y, 20, 200);

my_radian = 0.5f;
vector2_of_my_rect = Vector2.Transform(vector2_of_my_rect , Matrix.CreateRotationX(my_radian);`

I choose this use of the method Transform() because it looked like simple and seemed to don’t require to create each corner of my rectangle.

but when i use it, vector2_of_my_rect stay straight and don’t rotate at all.

I’m lost.

The Rectangle struct is axis-aligned, so it can’t hold rotation. It only has a position and size. If you want a rectangle with a rotation you should implement it yourself.

Thi is really weird because if you look at the definition of a Texture2D, you can find :
public Rectangle Bounds { get; }
and you can rotate it.

So it’s kind of stupid to not be able to do it with a simple rectangle.

I don’t get the logic here.

A Texture2D doesn’t hold rotation either, it’s just drawn rotated. You pass the rotation you want for your texture to your SpriteBatch instance and it draws the texture with that rotation, but the texture itself is not rotated, the quad you draw it to is.

@Jjagg ok i understand now

Then maybe you can help me,
i have a Rectangle rect_laser that will

  • be rotated at a specific angle
  • grow in size
    These treatments have to be done in my Update() to detect collision with another (non moving) Rectangle rect_destination.

I’ve seen that i can do it with Vector2.Transfrom() if i create 4 corners of a Rectangle and rotate each one of them.
Then i create :

corner1 = Vector2.Transform(corner1, Matrix.CreateRotationX(tangent));
corner2 = Vector2.Transform(corner2, Matrix.CreateRotationX(tangent));
corner3 = Vector2.Transform(corner3, Matrix.CreateRotationX(tangent));
corner4 = Vector2.Transform(corner4, Matrix.CreateRotationX(tangent));

But i don’t understand how to apply these corners rotations to my Rectangle rect_laser and how to Draw it.

Can you help me ?

maybe i’ve understood, i’m trying something :slightly_smiling:

You can’t apply the rotation to a Rectangle, so I recommend writing your own rectangle struct/class that can handle rotation. When drawing you can pass rotation and the non-rotated rectangle to spritebatch in stead of passing a rotated rectangle. With your own class you can save rotation as a float since it’s just in 2D. In this case using matrices complicates it all a bit IMHO, also if you do use matrices you should rotate around the Z axis and make sure you rotate around the center of the rectangle or you’ll move it as well.

before i was using roataion of Draw() but it doesn’t detects correct collision.
To explain :

i trace a laser beam with a rectangle at a certain angle, and when the laser collide with another rectangle bound . I stop the laser.
So if i use rotation only with draw, that means that if the laser have a big angle orienation :

  1. it will trace the laser straight
  2. it will collide with bound
  3. it will be drawn rotated
  4. laser will appear shorter thant expected and not touching bound because of the collision done while laser was straight

So i can’t do it with Draw().

I have a trick to solve my issue but it’s kind of ugly :
It’s making the length of my laser twice as expected in order to have long enough to be visually passing on bounds but it will be hard to balance without looking buggy.

This will be way easier if you split up drawing from your collision detection logic. You don’t have to use the same rectangle for both (in most cases you don’t want to). What I keep saying here is that you can’t have rotation in Rectangle, so you can’t use it directly for your collision detection. If you implement your own rectangle that can have rotation it’s easy to check for collision with another rectangle. If you want to use the same rectangle for drawing you can get the data you need to pass to spritebatch from it.

RotatedRectangle rotatedRect = /*...*/; // has position, size and rotation
Rectangle rect = rotatedRect.ToRect(); // holds position and size without rotation
Vector2 origin = rect.Size.ToVector2() / 2f; // put the origin in the center of the rectangle so rotation is applied correctly
spriteBatch.Draw(laserTexture, null, rect, null, origin, rotatedRect.Rotation);

Something like that probably.

IF you are interested, I can show you how to do an easy collision detection on any polygon…
Except for CONCAVE shapes, you should define 2 seperate shapes for that…

Lets take an enemy cigar shaped ufo as an example…

It will have a diamond shaped hit-detection shape, because that fits the overall shape of a ufo, while not having a lot of details… And that shape is a good example of a rotated and deformed rectangle…

We will check for hits against the tip if a laser. But it could be any point…

HERE GOES:
The UFO class contains a list vector2s called “corner_points”…

To this list we add a vector2 for each point we want to define for our poly… Use graph paper or paint to plan these coords on your ufo…
So in this case, 4 points, at the extremities of the UFO…

When the UFO has this LIST of vector2s, you can imagine a line between each… Now all you need to do is determine if the LASER-tip-position is on the INSIDE of each line…

THIS method, takes 3 variables: line start, line end, and point to test against, and RETURNS a value in negative or positive for above or over…

public static float underOroverTheLine(Vector2 lineStart, Vector2 lineEnd, Vector2 point)
{
float Ax = lineStart.X;
float Ay = lineStart.Y;

        float Bx = lineEnd.X;
        float By = lineEnd.Y;

        float Cx = point.X;
        float Cy = point.Y;

        return (Bx - Ax) * (Cy - Ay) - (By - Ay) * (Cx - Ax);
    }

So test against each line, and if the laser is on the inside of EACH line, you have collision…

For enemy rotation, you simply ROTATE each vector 2 around a central point (center of our UFO)
with THIS method: Overloads are self explanatory I think:

public static Vector2 RotateVector2(Vector2 point, float radians, Vector2 pivot)
{
float cosRadians = (float)Math.Cos(radians);
float sinRadians = (float)Math.Sin(radians);

        Vector2 translatedPoint = new Vector2();
        translatedPoint.X = point.X - pivot.X;
        translatedPoint.Y = point.Y - pivot.Y;

        Vector2 rotatedPoint = new Vector2();
        rotatedPoint.X = translatedPoint.X * cosRadians - translatedPoint.Y * sinRadians + pivot.X;
        rotatedPoint.Y = translatedPoint.X * sinRadians + translatedPoint.Y * cosRadians + pivot.Y;

        return rotatedPoint;
    }

If you use FORLOOPS to iterate through all the lines for rotation, and BREAK the loop at the first failed check, its fast enough for a good amount of simultaneous stuff…

This isnt fool-proof detection… There are always things to take into account, like bullets can still go THROUGH narrow shapes, and miss the collision…

This might not be in any math book but i took some time one day to figure out how to combine a 2d dot and cross product i did this back when xna was around.

Its a alternate way to do it, im not sure which is faster in real conditions.

This is a combined (cross right and dot product)
It basically works just like the above line segment to point check monopalle posted.
Its a little more raw and doesn’t need a transform.
If you have a rotated rectangles points you can find its lines in order starting from,

topleft - topright = direction A
then from
topleft - somecollisionpoint = B

you have two directional vectors. Then for the function cross right that implies you started from the top left,_ the function will return true if the point is to the right side of the line segment_. You would need to check each line to a point moving from point to point in a clockwise fashion, and get the same result back each time for all 4 rectangle lines if they are all true or false against that point they are within.

public static float CrossRightAndDot2d(Vector2 A, Vector2 B)
{
return A.X * B.Y + A.Y * -B.X;
}

The reverse of the function is the below for the left cross and dot.
For just a rectangle either works fine.

public static float CrossLeftAndDot2d(Vector2 A, Vector2 B)
{
return A.X * -B.Y + A.Y * B.X;
}

This can be used on the rotated rectangles points and a rotated collision point.
As it is basically working off of the signs generated by the cross and dots of those found vectors.

i had a line segment to line segment intersect test some were but i cant find it.

SpriteBatch also has a texture origin offset that will move then center point drawing or if you like the rotation origin offset though its prolly better to adjust it yourself positionally.
It is rather annoying, i think i had a forum chat with hargraeves about it.
This is how i used to do it in xna, not very new guy friendly if you ask me,

    public void DrawReAlignedRotatedRectangle(Texture2D textureobj, Rectangle screenrect, Rectangle texturerect, float rot, Color c)
    {
        screenrect.X += (int)(screenrect.Width * .5f);
        screenrect.Y += (int)(screenrect.Height * .5f);
        Vector2 toff = new Vector2(texturerect.X + texturerect.Width * .5f, texturerect.Y + texturerect.Height * .5f);
        spriteBatch.Draw(textureobj, screenrect, texturerect, c, rot, toff, SpriteEffects.None, 0);
    }

What you’re actually doing is checking the magnitude of the cross product of the vectors (though you add a 0 for the z-component since we’re in 2D). To find if a vector is clockwise or counter clockwise from another vector in 3D, you can check the sign of the cross product: positive means the second vector is oriented clockwise and negative means it’s counter clockwise of the first. Since this works in 3D of course it also works in 2D as well :slightly_smiling:

Here’s the maths:
Since p1 x p2 = ||p1|| ||p2|| * sin(alpha) where alpha is the oriented angle between the two vectors and ||v|| is always positive, a negative cross product means sin(alpha) < 0. That in turn means your angle is in the range (0, -PI) which means p2 is counter clockwise of p1. Another interpretation is that the point p2 is to the right of vector p1.

I think he is actually stepping a point thru time and positions to find a collision.

To be honest i don’t like any of this. what i really think he needs here is a Ray to Line Intersects test. Not a a point to rectangle test at all. Now that i think about it thats more for like missles or bullets not a lazer which is basically a ray after all.

What he probably should be doing is reverse rotate the point by the rectangles rotations centered on the rectangles center as the rotational origin. As well as reverse rotating the lazers firing direction.
Then calculate a ray into a non rotated rectangle at the same position.
Find the point of contact on the surface then the rotate that point back and then rotate the rectangle with spritebatch to screen as well as the explosion position drawing. That is quite a bit to do in order to do it properly but steping a point thru a number of positions is going to be even more work.

Because spriteBatch is not going to return the rotated rectangles corner points. He could do that himself on each rectangle point and use the above methods with stepping or rotate the point and use the above methods with stepping from a close position but in either and all cases

I think a ray to rotated rectangle intersects method, would be nice to already have in mono-game that does this for the user, especially considering how many people do 2d stuff.
A quadratic intercept should also be around some where, i had to find one that didn’t work right and then alter it to get it to actually work properly.

Anyways you should be able to find just about any algorithm somewhere here.
http://www.faqs.org/faqs/graphics/algorithms-faq/

btw…
Those are true 2d cross and dots products combined, there is no z component required. They are neither a dot nor a cross they are actually both at once. To say if you just want to know if a ray/plane and a line segment cross each other the below will work…
For a real ray you have to do just a regular dot n against a and b as well.
for the ray both results would have to be positive or negative i forget.

    public bool PlanelineSegmentIntersect(Vector2 s, Vector2 e, Vector2 s2, Vector2 e2)
    {
        Vector2 n = e - s; // forms a direction vector
        Vector2 a = s2 - s;
        Vector2 b = e2 - s;
        float c = CrossRightAndDot2d(n, a); // treats the direction
        float d = CrossRightAndDot2d(n, b); // as a clockwise plane

        if (c < 0 && d < 0 ||  d > 0 && c > 0)
            return false;
        else
            return true;
    }

I was playing around trying to make a cheap cos version and i found this one.

    public static bool LineSegementsIntersect(Vector2 p1, Vector2 p2, Vector2 q1, Vector2 q2, out Vector2 intersection)
    {
        intersection = new Vector2();
        var r_pdif = p2 - p1;
        var s_qdiff = q2 - q1;
        var rxs = Cross(r_pdif, s_qdiff);
        var qpxr = Cross((q1 - p1), r_pdif);
        // If r x s = 0 and (q - p) x r = 0, then the two lines are collinear.
        // 3. If r x s = 0 and (q - p) x r != 0, then the two lines are parallel and non-intersecting.
        if ( (rxs == 0 && qpxr == 0) ||  (rxs == 0 && !(qpxr == 0))
            return false;
        // t = (q - p) x s / (r x s)
        var t = Cross((q1 - p1), s_qdiff) / rxs;
        // u = (q - p) x r / (r x s)
        var u = Cross((q1 - p1), r_pdif) / rxs; 
        // 4. If r x s != 0 and 0 <= t <= 1 and 0 <= u <= 1
        // the two line segments meet at the point p + t r = q + u s.
        if (!(rxs == 0) && (0 <= t && t <= 1) && (0 <= u && u <= 1))
        {
            // We can calculate the intersection point using either t or u.
            intersection = p1 + t * r_pdif;
            return true;
        }
        // 5. Otherwise, the two line segments are not parallel but do not intersect.
        return false;
    }
    public static float Cross(Vector2 v, Vector2 v2)
    {
        return v.X * v2.Y - v.Y * v2.X;
    }

I think that was exactly what you were looking for at first.
I doubt you can get it much cheaper then this, i tested it a little it seems to work.

1 Like