Jump to content
  • Advertisement
Sign in to follow this  
redneon

Rotate Tetris Shapes

This topic is 4399 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to get into Microsoft's XNA Game Studio Express thing so I thought I'd write a Tetris game to get into using C# and GSE. I've run into a little problem though which I'm hoping someone can help me with. I have a 2D array of Block objects which was created like this:
Block[,] gameGrid;
gameGrid = new Block[10, 18];

for (int x = 0; x < gameGrid.GetLength(0); x++)
{
    for (int y = 0; y < gameGrid.GetLength(1); y++)
    {
        gameGrid[x, y] = new Block(false, Color.Red, posX + (blockTexture.Width * x), posY - (blockTexture.Height * y), blockTexture.Width, blockTexture.Height, x, y);
    }
}



The first parameter of the Block constructor sets the blocks to be disabled so that they don't show up. Below is a screenshot of the grid with every block enabled to give you an idea of what it looks like: What I'm wanting to do is rotate the blocks but I'm not sure how to do it. For example, take the following scene: The green block is the centre block which the others will be rotated around. The desired effect is the following: What I need to do is calculate which blocks need to be disabled and which blocks need to be enabled and aside from having lots and lots of if statements, I can't see how I'm going to do it. I think the calculation for each block needs to be relative to the block to be rotated around. For the above shape, each block is adjacent to the centre block. But what about the following: Which needs to end up looking like this: Sorry for all of the images, but you know what they say? A picture's worth a thousand words =o) Can anyone help?

Share this post


Link to post
Share on other sites
Advertisement
Guest Anonymous Poster
Each tetris shape is a series of blocks that have a position relative to each other.

So the most convenient way to represent a tetris shape is as a set of coordinates (representing the blocks) and a coordinate origin. For example, the 'triangle' shape might be the following blocks:

(0, 0), (0, 1), (-1, 0), (1, 0)

Now you just have to rotate it around the adequate block (in this case, (0,0)).

This is just multiplying each coordinate in the shape by a 90 degree rotation matrix, and you're set!

To make things simpler, choose your coordinate system so that the rotation is always performed around (0,0).

Eg. for a right rotation multiply each coordinate in the shape with the matrix:

0 -1
1 0

Share this post


Link to post
Share on other sites
Because I'm using a 2D array, I do have a coordinate system for the blocks. For example, gameGrid[3, 2] is the fourth block in on the third line up.

I'm going to have to refresh my memory on matrix multiplication though as I've no idea how to go about implementing what you suggested =o)

Share this post


Link to post
Share on other sites
I've used this rotation-around-central-brick method as well, but it then resulted in a kind of weird semantics. For instance, imagine rotating the square block ('O' block) -- in classic Tetris it doesn't rotate when you press the rotate key, however with this design, you have to choose a 'central' brick and the block then rotates around one of its corners.

In the end I went for a more hackish and simpler method -- I just defined a list of all possible shapes for every block (expressed in relative coordinates to the central brick) and when the rotation key is pressed, the next shape is chosen. This allows me to set only one shape for the 'O' block, resulting in no rotation happenning when the user presses the rotation key.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Because I'm using a 2D array, I do have a coordinate system for the blocks. For example, gameGrid[3, 2] is the fourth block in on the third line up.
That's the coordinates of the blocks in the tetris game board. It gives you no information as to how a block should be rotated.

You need another coordinate system for each shape, so each block in a shape knows where it stands in relation to the other blocks in a shape. This is necessary because blocks rotate in a different way depending on which shape they're in.

Quote:
I've used this rotation-around-center-brick method as well, but it then resulted in a kind of weird semantics. For instance, imagine rotating the square block ('O' block) -- in classic Tetris it doesn't rotate when you press the rotate key, however with this design, you have to choose a 'central' brick and the block then rotates around one of its corners.
With all due respect, the weird semantics are entirely your doing.

If the square block shouldn't rotate, erm, don't rotate it?

You don't have to choose a 'central' brick or anything of the sort. You just have to NOT DO ANYTHING in response to the rotate command if the shape is a square. How hard is doing nothing at all? :)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Well, I'm bored so I wrote it up in python.

Disabuse yourself of the notion that things with the word 'matrix' in them are hard. Here's all the code we need to display AND rotate any shape around the (0,0) coordinate (shapes are just lists of coordinates. I think it's pretty self-explanatory; this rotates things to the left, rotating them right just means reversing the signs in rotate_pt_left:


def display(shape):
for y in range(-3,3):
print '\n',
for x in range(-3,3):
if (x, y) in shape: print '#',
else: print ' ',

def rotate_pt_left(point):
return (point[1], -point[0])

def rotate_left(shape):
return [rotate_pt_left(point) for point in shape]



Now, let's make a function that shows us the four rotations for a given shape. Also, let's define two test shapes, the triangle and the z shape:


triangle = [ (0,0), (-1,0), (1,0), (0,1) ]

z_shape = [ (0,0), (1, 0), (0, 1), (-1, 1) ]

def show_rotations(shape):
current = shape
for i in range(4):
display(current)
current = rotate_left(current)



And now, let's display them!


>>> show_rotations(triangle)




# # #
#



#
# #
#



#
# # #




#
# #
#

>>> show_rotations(z_shape)




# #
# #



#
# #
#



# #
# #




#
# #
#

>>>



Easy. Don't make it harder than it has to be.

So you keep track of shape positions instead of individual blocks in your tetris world, and just add the shape's position to each block to get the block's position in the tetris world. Rotation just depends on the shape, so it needs no knowledge of the tetris world (the converse is not true: a rotation might be illegal, but the rotation function needn't know about it).

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Quote:
I've used this rotation-around-center-brick method as well, but it then resulted in a kind of weird semantics. For instance, imagine rotating the square block ('O' block) -- in classic Tetris it doesn't rotate when you press the rotate key, however with this design, you have to choose a 'central' brick and the block then rotates around one of its corners.
With all due respect, the weird semantics are entirely your doing.

If the square block shouldn't rotate, erm, don't rotate it?

You don't have to choose a 'central' brick or anything of the sort. You just have to NOT DO ANYTHING in response to the rotate command if the shape is a square. How hard is doing nothing at all? :)


Yes, I could've hardcoded some switch block that would just look what kind of block it is and perform the appropriate action, only I thought that'd be an ugly solution and tried to make a generic block rotation method. [smile]

Share this post


Link to post
Share on other sites
Am I right in thinking that that code only works in a 9 (3x3) block area? In which case, if I changed the -3 to -4 and 3 to 4 would it work for the long shape?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Am I right in thinking that that code only works in a 9 (3x3) block area? In which case, if I changed the -3 to -4 and 3 to 4 would it work for the long shape?
No and yes. :)

It only DISPLAYS the points in the range x in (-3, 2) and y in (-3, 2). That's just my crummy display function, which isn't important. Make it bigger if you want, as you said. But you'll be using a different, non-ascii display function anyway.

The actual rotation doesn't depend on magic numbers; try the point (-234, 1000) and see for yourself. It works for any coordinate (ergo, shapes can have coordinates within any range).

Share this post


Link to post
Share on other sites
When I wrote tetris using XNA, I decided that all blocks would be represented by 2D arrays, which may or may not be completely filled.

Thus, the 'L' block became


#@##
#@##
#@@#
####


Which gives us a neat 4x4 square which is very easy to rotate. For collision detection, just only consider the 'filled' areas of the array. In the original tetris, am I right in assuming this piece rotates around the mid point of this 4x4, as opposed to any one square in the piece itself? I'm pretty sure it works that way.

Similarly, the 'square' shape can be represented by something like


####
#@@#
#@@#
####


or even


@@
@@


and so doesn't move when you rotate it. You can take a similar appraoch with all the shapes. They don't have to be all the same size array, or even to have the same width as they do height. Just play around with the size until you're happy with the rotation behaviour. No need to code exceptions for any of the shapes that way.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!