0

I have four 32 x 32 rectangles that I use for my game character (collectively they are a ship and each of the rectangles represents a cell (ship compartment) that has it's own collision detection system).

I keep these cells together in a 2x2 format. Moving the 'ship' along the X and Y axes is all fine. However, when I rotate the 'ship', the individual rectangles rotate and face the correct direction, but they are no longer 'together'. That is to say, rectangle A1's right border is out of sync with rectangle A2's left border, and so on...

How do I rectify the rectangles' positions so they are still aligned after rotation? This is my first game and I'm not a maths person, thus I find myself asking for your expertise in this matter!

Many thanks in advance for your assistance. If you require more information (i.e., code) then I will provide!

UPDATE:

I finally got this working! Below is my code. I hope this helps others!

//The point we want to rotate around (in this example, I was rotating around another ship)
Vector2 origin = new Vector2(selectedShip.Position.X, selectedShip.Position.Y);

test1.Position = Vector2.Transform(test1.Position - origin, Matrix.CreateRotationZ(testRot)) + origin;
test2.Position = Vector2.Transform(test2.Position - origin, Matrix.CreateRotationZ(testRot)) + origin;
test3.Position = Vector2.Transform(test3.Position - origin, Matrix.CreateRotationZ(testRot)) + origin;
test4.Position = Vector2.Transform(test4.Position - origin, Matrix.CreateRotationZ(testRot)) + origin;

// Alter the rotation of the four ship compartments for drawing
test1.Rotation += testRot;
test2.Rotation += testRot;
test3.Rotation += testRot;
test4.Rotation += testRot;

// Update rectangle positions
test1.Rect = new Rectangle((int)test1.Position.X, (int)test1.Position.Y, ship01Texture.Width, ship01Texture.Height);
test2.Rect = new Rectangle((int)test2.Position.X, (int)test2.Position.Y, ship01Texture.Width, ship01Texture.Height);
test3.Rect = new Rectangle((int)test3.Position.X, (int)test3.Position.Y, ship01Texture.Width, ship01Texture.Height);
test4.Rect = new Rectangle((int)test4.Position.X, (int)test4.Position.Y, ship01Texture.Width, ship01Texture.Height);

theSprite.Draw(ship01Texture, test1.Rect, null, Color.White, test1.Rotation, Vector2.Zero, SpriteEffects.None, 0.0f);
theSprite.Draw(ship01Texture, test2.Rect, null, Color.White, test2.Rotation, Vector2.Zero, SpriteEffects.None, 0.0f);
theSprite.Draw(ship01Texture, test3.Rect, null, Color.White, test3.Rotation, Vector2.Zero, SpriteEffects.None, 0.0f);
theSprite.Draw(ship01Texture, test4.Rect, null, Color.White, test4.Rotation, Vector2.Zero, SpriteEffects.None, 0.0f);

Big thanks to everyone that helped!

  • Rotation is function of angle(for example) and point around what you are rotating. Are you sure the point is same for all your rectangles? – wondra Jan 31 '14 at 11:30
  • The origin of all the rectangles should be set to the center of the rectangle, which is already the rotation point. Try this: RotateAboutOrigin(new Vector2(test1.Width / 2, test1.Height / 2), Vector2.zero, rotation) – pid Jan 31 '14 at 16:29
  • Thanks @pid, I tried that and now I can rotate my 'ship' around a point. This point, however, is not the center of the 'ship', it is outside the craft. It is likely I am mixing up my logic. What I have now I can probably use later on for making the 'ship' orbit a body (i.e., a planet). I'll update my question with more information. Also, thanks for updating your answer - it's been helpful to me and I'm sure it will be a great help to those other XNA beginners out there! – user3256944 salutes Monica Feb 01 '14 at 11:59

2 Answers2

3

From your question I'm assuming you started at the left and ended up with the middle image instead of the right.

enter image description here

The difference between the images in that the middle image the rectangles are all rotated around their individual centers instead of all being rotated about the same point.

See here for how to rotate around a given point

Community
  • 1
  • 1
James
  • 9,774
  • 5
  • 34
  • 58
  • Yes this is exatly my problem. Thank you for providing the link. Please see my editted question, I hope you can provide further assistance! – user3256944 salutes Monica Jan 31 '14 at 13:46
  • I wrote that code from the other link. In your implementation, user3256944, you are implementing it wrong. The 'origin' means the location that all the objects are going to rotate around (not the origin of the specific object being rotated). So when you rotate all 4 rectangles, they should all be passing the EXACT same origin value. But you are sending a different origin value for each object... not good. – Steve H Jan 31 '14 at 18:49
  • @SteveH Thanks for correcting me. I was trying to point to the center point (origin) by getting the corner of the individual rectangles that 'touched' the centre point. In other words, the centre point from the top-left rectangle was (32,32), bottom-left was (0, 32) etc. I've now changed my flawed logic! – user3256944 salutes Monica Feb 01 '14 at 11:36
  • here's a graphic to help visualize the rotation: https://fppkua.dm1.livefilestore.com/y2pPjn8tPSqDn1yMQdNEVolY3cdTgxyAs6d_27q2SFxm1R5ITy6RVzo-vaHUgbpmbA1TkIjZmMl-hsHcb_GgF7jZNwnagyUo_Xmz7CuxA6Wh_Y/rotation_origin.jpg?psid=1 – Steve H Feb 01 '14 at 13:53
  • Thanks for the diagram @SteveH, it's helped a lot and it clearly defines what I'm trying to achieve. I've altered my code yet again, still one issue outstanding with the ship compartment rotations unfortunately! Where am I going wrong? – user3256944 salutes Monica Feb 01 '14 at 15:19
2

Anchor the rectangles at their center, not one of the four vertices.

You'll have an hierarchical structure:

  • a collection with a translation (the position of the center of the collection)
  • for each element in the collection you'll have a relative position to the collection's center

At that point, you'll have to rotate the position of the rectangles and the rectangles themselves this way:

  • rotate element at origin (before translation)
  • rotate relative position
  • add absolute position and relative position
  • translate rectangle

This is a little diagram:

+-----+-----+
|     |     |
|  e  |  e  |
|     |     |
+-----C-----+
|     |     |
|  e  |  e  |
|     |     |
+-----+-----+

C is the center of the collection, e are the centers of the elements. The relative position is the vector e-C. This is pretty basic stuff, it may sound difficult but it's just a matter of adding/subtracting vectors (positions) and rotating them by angles in the right order.

The order of translating/rotating the elements/collection is very important.

To rotate around the center of the rectangle:

RotateAboutOrigin(new Vector2(test1.Width / 2, test1.Height / 2), Vector2.zero, rotation)

At this point translate by the relative position, which is one of these (one line for each rectangle):

Vector2 p1 = new Vector2(+test1.Width / 2, +test1.Height / 2)
Vector2 p2 = new Vector2(+test2.Width / 2, -test2.Height / 2)
Vector2 p3 = new Vector2(-test3.Width / 2, +test3.Height / 2)
Vector2 p4 = new Vector2(-test4.Width / 2, -test4.Height / 2)

The actual mapping of relative translations to the rectangles has to be determined, here I just try to give an idea. By changing the actual lines up/down the right combination will be easy to find.

Finally, translate by the center of the cluster:

p1 + c // c is also a Vector2

All this code can afterwards be corrected and optimized by removing a lot of excess code and saving vectors in appropriate places. Especially the CreateRotationZ() inside RotateAboutOrigin should be cached, like this:

Matrix[] rot = new Matrix[64];

for(phi = 0; phi < 64; phi++)
{
    rot[phi] = Matrix.CreateRotationZ(phi / 64 * 2 * Math.PI);
}

In the example above you'll then have 64 matrices and a 64 step-wise rotation. You can then rotate only by discrete multiples of the minimum angle 1 / 64 * 2 * Math.PI. This will make the function much faster.

pid
  • 11,472
  • 6
  • 34
  • 63