Sign in to follow this  
redneon

Rotate Tetris Shapes

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
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
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
It seems like the Python method is the correct way for me to go but I feel really stupid in saying that I just don't understand what's going off.

On my current grid I nominate four of the blocks as the current shape so what I could do is nominate one of those blocks as the centre block and then calculate the other blocks' relative positions to the centre block. This would give me the coordinates in the form you specified. I just don't know what to do from that point.

I have uploaded the code to the following location:

http://darrell.dunmanifestin.co.uk/Tetris.rar

I'd be really grateful if someone could take a look at it and tell me if what I'm thinking of is a viable solution.

Share this post


Link to post
Share on other sites
I did something cool sometime, with real time collision for block. You can take a look at the code if you want :
http://www.rndlabs.ca/daivuk/TP/14/David_StLouis_TP2_Disco_Tetrix.zip
I think I was using quadtrees (overkill lol)

Share this post


Link to post
Share on other sites
Cool. I'll take a look.

I've just realised that the link I've provided is a corrupt archive. I'll post a fixed one on Sunday as I'm in Manchester until then to watch England play Macedonia.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this