Block rotation in tetris?

Started by
6 comments, last by GameDev.net 18 years, 8 months ago
Hello, I was wondering how I could rotate blocks in tetris. In my game right now I have rows and columns and each shape has blocks in different cols and rows. I was thinking I could just say move up two and over two or something. But what about the walls and other blocks. What makes it so the shape can or can't rotate? I mean what would be a good way of telling you can rotate sometimes but if its next to a wall or other block then it can't?
If you insist on saying "DUH", try to make a post that makes a little more sense
Advertisement
To rotate a piece you can rotate the position of each of the blocks it is made of seperately. First, express the position of each block relative to the one you want to rotate around. For example the block to the right of the one you're rotate around would have position (x, y) = (1, 0). Then the rotated position of the block would be (y, -x), or a rotation in the other direction is (-y, x).

Which rotation is clock-wise and which is counter-clockwise depends on if y increases going up or down.

To test if the rotation is possible just check if the rotated posion of each block works or not. If the new position is outside the game field or on another block, don't allow the rotation.

If you want to derive the rotation stuff yourself try taking some equations for rotation or a rotation matrix and plug in 90 degrees.

Hope that helps.
Well I've never made tertis (nor do I intend to [smile]) but if you imagine that a falling shape is comprised of blocks then each possible shape (if not randomly generated, but they usualy arent, so thats good) can be stored in a small 6x6 (or bigger) char array where each array element indicates the presense of a block and block colour(or 'color' if your american) to make up a shape.

OK, so to determine if a shape is touching (colliding) with any other blocks or the floor simply go through each block of the shape and compare it against each block on the screen (there are faster ways - thats the easiest but sadly the slowest method) and test if they touch (you might already have that bit sussed)

Now we can extend that system so that a shape is actually 4 such arrays of blocks - one array for each orientation - then when you want to rotate the shape just make sure that none of the blocks of the desired orientaion overlap with currently existing blocks.

This method has two advantages: 1- its easy to implement and 2- its flexible so you can have shape change shape when you rotate them which would be fun for the harder levels of your tetris :)

Hope that was some help :)
My tetris game (that I didn't finish) stored each block as a 4x4 grid. Then I rotated inside of that grid:
xxxx
ooox
oooo
oooo

Would rotate to:
ooox
ooox
ooox
ooxx

Then to do colision I just checked against each node in the grid.
On determining whether a block can rotate:

Check to see if the new rotated piece overlaps anything. If it does, start checking it at positions to the side of its current position. One block to the left, one block to the right. Two blocks left. Two blocks right. Stop checking as soon as it fits. If it doesnt fit anywhere within two blocks left or right it can't be rotated.

This is what I do in my tetris and it works great. You can also use it against the border of the game field, not just the blocks that are filled.
thanks for the posts so quickly, I think I have a good idea of what I need to do, thanks
If you insist on saying "DUH", try to make a post that makes a little more sense
I would not try to programmatically rotate the blocks. It's not that it doesn't work, but it generally gives results that suck. Just pre-compute the coordinates of each block in each rotation and store them in an array.

If you think of all your pieces as relative to an upper-left corner, then manually rotate each block such that it stays flush with the top and left. Then as you move that reference point down, the block moves with.

your block would look like
 ____  _____  ____  ____| o   | o    |ooo  |o    |ooo  |oo    | o   |oo   |     | o    |     |o      |     |      |     |      // store the (x,y) coordinates of each brick for each rotation:int t_block[4][4][2] = { { {1,0}, {0,1}, {1,1}, {2,1} },  { {1,0}, {0,1}, {1,1}, {1,2} },  { {0,0}, {1,0}, {2,0}, {1,1} },  { {0,0}, {0,1}, {1,1}, {0,2} },};// then to try to see whether you can rotate, or move the block down,// just test whether the new position causes any of the bricks to occupy// a space in the pit that is already occupied:const int pit_width = 10;const int pit_height = 20;int pit[pit_width][pit_height] = { {0} };int try_pos(int block_x, int block_y, int block_test[4][2], int pit[pit_width][pit_height]){    for(int i = 0; i < 4; i++)    {        if(pit[block_x + block_test[0]][block_y + block_test[1]])            return false;    }    return true;}// the rest is easy.int move_block_down(){    if(try_pos(block_x, block_y + 1, block[cur_pos], pit))        block_y++;    else;  // hit bottom}int rotate_block(){    if(try_pos(block_x, block_y, block[(cur_pos + 1)%4], pit))        cur_pos = (cur_pos + 1) % 4;    // else rotation is blocked}


the only exception to the flush top-left rule is the schlong block in its vertical position, where it should be in the x=2 column.

--ajas
I have written a few tetris like games. When i made my first one i had exactly the same problem as you.

Then i realised that every tetris piece contains of four blocks. I used this to create a offset array for each block for each of the 4 rotations, so for the L, shape i have (Delphi):

Type TBrick = class
XOff : Array[1..4, 1..4] of Integer;
YOff : Array[1..4, 1..4] of Integer;
end;

Where the first dimension of the array is for the rotation and the second is for the offsets. I load all the information from files and then for rendering and collision detection all i need to do is use a simple for loop and test 4 times:


procedure TBrick.Render(XPos, YPos: Integer);
var Counter: Integer;
begin
brickTextures[ Piece.Texture ].Bind;

glPushMatrix();
glTranslatef(XPos, YPos, 0);
glScalef(BLOCK_SIZE, BLOCK_SIZE, 1);

glTranslatef(X-1, 20-Y, 0);
For Counter:=1 to 4 do begin
glPushMatrix();
glTranslatef(XOff[Orientation][Counter], -YOff[Orientation][Counter], 0);
glCallList( planeList );
glPopMatrix();
end;
glPopMatrix();
end;

.. and collision...

function TLevel.Colission(Brick: TBrick): Boolean;
var Counter: Integer;
var Element: TPoint;
begin
Result:=False;

For Counter:=1 to 4 do begin
Element:=Brick[Counter];

Result:=Result or (Level[ Element.X, Element.Y] 0);
end;

end;

Where Level is a 2 dimensional array discribing the level (borders and filled blocks)

/Andreaz - www.glxtreem.net


This topic is closed to new replies.

Advertisement