4
\$\begingroup\$

I'm making Tetris in Java and am at the point of rotations... Originally I was hardcoding each rotation:

if (direction.equals("right")) {
            if (shape.equals("Bar")) {
                if (rotationsCounter == 0) {
                    currXs[0] += 1;
                    currYs[0] += -1;

                    currXs[1] += 0; 
                    currYs[1] += 0; 

                    currXs[2] += -1; 
                    currYs[2] += 1; 

                    currXs[3] += -2;    
                    currYs[3] += 2;             

                    rightRotate1 = new int[] {currXs[0], currYs[0], currXs[1], currYs[1], currXs[2], currYs[2], currXs[3], currYs[3]};          
                }       
                if (rotationsCounter == 1) {  
                     etc...

Then, I have this to set the correct coordinates based on what the rotated counter is

   if (direction == "right") {
            if (shape == "Bar") {
                if (rotationsCounter == 0) {    
                    pieceRotations = rightRotate1;                      
                }       
                if (rotationsCounter == 1) {
                    pieceRotations = rightRotate2;      
                }                   
                if (rotationsCounter == 2) {
                    pieceRotations = rightRotate3;  
                }   
                if (rotationsCounter == 3) {
                    pieceRotations = rightRotate0;  
                }               
            }
        }
        if (direction == "left") {
            if (shape == "Bar") {
                if (rotationsCounter == 0) {    
                    pieceRotations = leftRotate3;                       
                }       
                if (rotationsCounter == 3) {
                    pieceRotations = leftRotate2;       
                }                   
                if (rotationsCounter == 2) {
                    pieceRotations = leftRotate1;   
                }   
                if (rotationsCounter == 1) {
                    pieceRotations = leftRotate0;   
                }
            }           
        }
        return pieceRotations;

But found that was a very tedious way to go...

People suggested I use rotation matrices in Linear Algebra.

So I tried rotating 1 coordinate in a Tetris piece just to see if I was doing it correctly... the point (1, 1) seems to rotate just fine...

enter image description here

So then I thought that the way to rotate the whole block was to get all the coordinates of each tile in a Piece (4 tiles, 16 coordinates), and rotate each one... but I was wrong.

enter image description here

So my questions is...

In the first picture, I choose (1, 1) as my rotation axis... How do I move the rest of the coordinates in relation to that point?

Thanks!

\$\endgroup\$
6
  • 2
    \$\begingroup\$ I know this isn't an answer but, honestly? I think you're attempting an overly complicated solution for the problem. Assuming you're perfectly emulating Tetris, I would have probably simply had each shape as 8 ints (four blocks in 2 dimensions), and each set of possible rotated shapes within an array of 32 ints (2 dimensions x 4 blocks per shape x 4 shapes). Since there are only, if I recall, 4 shapes, it's fairly trivial to "hard code" them all. This is assuming you aren't attempting some new form of Tetris (with, say, user-generated shapes). \$\endgroup\$
    – Attackfarm
    Apr 23, 2013 at 2:56
  • \$\begingroup\$ @Attackfarm there are 7 shapes. The issue is I wanted a slick solution that would make it dynamic for me to add custom shapes if I wanted instead of being bound to expand and alter a coordinates array each time \$\endgroup\$
    – user3871
    Apr 23, 2013 at 3:01
  • \$\begingroup\$ I forgot about the L shape (and ignored the mirror image shapes), but the gist is the same. Even if you added custom shapes, it's fairly trivial to code them in arrays. It could probably be done in a fraction of the time it would take you to learn a new process of math, let alone leading to code far easier to debug (any mistake is visible in the shape, instead of an odd, unexpected result). The only situation I could see, in a Tetris-y setting, utilizing matrix rotations are customized shapes that number an order of magnitude more than the number of shapes you're handling here. \$\endgroup\$
    – Attackfarm
    Apr 23, 2013 at 3:08
  • \$\begingroup\$ @Attackfarm well my current code for hardcoding the rotation of each shape for left and right rotation is shown above in a snippet... as you can see, it's already pretty hairy... Can you write some pseudo code that'd show a better way to do it? \$\endgroup\$
    – user3871
    Apr 23, 2013 at 4:24
  • \$\begingroup\$ As a note: This is simply how I'd do it, to place readability of code above a more general system, since generality isn't necessary -- int[4][8] bar = {{0, 1, 1, 1, 2, 1, 3, 1}, {1, 0, 1, 1, 1, 2, 1, 3}, ..}; -- The first 8 is the horizontal bar, second the vertical bar, the next two rotations would be identical to the first two -- Quite literally simply encoding, in a 4 by 4 grid, the coordinates of each of the four blocks in a shape, then encoding the same shape of the next rotation, etc for the 4 rotations. Sum the blocks' coords to the grid's coords for collision detection \$\endgroup\$
    – Attackfarm
    Apr 23, 2013 at 4:48

3 Answers 3

5
\$\begingroup\$

This answer still ignores the attempt to use matrix rotation, but I realized that there was a simple yet general solution.

First, assuming that the shape is encoded as coordinates of blocks in a grid, you have an arbitrary shape containing blocks with coordinates in the X and Y axes from 0 to n, where n+1 is the maximum size of a block (traditional Tetris shapes would fit a 4x4 grid). The classic Tetris bar (vertical) would be (1,0), (1,1), (1,2) (1, 3).

To rotate this shape, no matter what the form or size, you simply swap and invert axes.

enter image description here

To rotate clockwise, for every block in the shape, the new block's X would be the previous Y, and the new block's Y would be the inverse of X (n-x). The example rotated bar (now horizontal) would be (0, 2), (1, 2), (2, 2), (3, 2)

To rotate counter-clockwise, the new block's X is the inverse of the old block's Y and the new block's Y is the old block's X.

To put it more clearly:

  • Clockwise- x2 = y1 && y2 = n-x1
  • Counter - x2 = n-y1 && y2 = x1

This can be done easily in a single method, the two rotations are independent of previous rotations (you could keep rotating clockwise indefinitely and cycle through the same 4 shapes), the code is simple and easy-ish to understand, and it is general enough to apply to any 2D shape composed of blocks. In fact, this is general enough that you could easily rotate even a user-generated shape, let alone any custom shapes you create yourself.

\$\endgroup\$
4
\$\begingroup\$

you can concatinate 3 matrices

first a translation to put 1,1 at 0,0, then the rotation and then translate 0,0 back to 1,1

if you use affine transformation matrices this is easy

[1,0,-1][0,1,-1][0,0,1] * rotationMatrix * [1,0,1][0,1,1][0,0,1]

if you don't use affine transformations then just subtract 1,1 on each point then rotate around 0,0, then re-add 1,1

\$\endgroup\$
2
\$\begingroup\$

You are experiencing a 2D version of a common rookie 3D mistake: order of transformation matters. Matrix multiplication is not commutative, i.e. A * B is different from B * A. If you translate the Earth to its correct orbital radius before you rotate it according to the 24 hour clock, you will cause the earth to move along its orbital path (rotating a translation, rather than translating a rotation).

You ostensibly are only performing one rotation transformation. However, your block points were already translated to their position before you began rotating them. @ratchetfreak suggested that you 1. undo the linear translation, 2. apply the rotation, 3. reapply the translation. That certainly would solve your problem, but I would suggest not applying the translation in the first place.

Your T-piece could occupy coordinates relative to its center of rotation (no 0-positions here!)

[(-1, -1), (1, -1), (1, 1), (2, -1)]

Now if you apply your R(90) 2D rotation to these points, they will change to

[(1, -1), (1, 1), (-1, 1), (1, 2)]

And finally you can add your translation (1, 1),

[(2, 1), (2, 2), (1, 2), (2, 3)]  
// nobody wants to occupy coordinate (0,0), right?
\$\endgroup\$

You must log in to answer this question.

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