Public Group

# Piece Rotation?

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

## Recommended Posts

I'm making a Tetris game using SDL. I'v think about everything ( and it should all work ) but the piece rotation. The way the game render, is that i create 4 square of the same size, and create them at a location ( the square form the piece ) I can move them down, left and right, but i have NO idea how i can rotate them. Is there a math formula that could help me on that? the zone when you play is 100x200 pixel. Each square use 20x20 pixel If you have an idea, how a website, or even an exemple on how to do that, I'll be happy Thank.

##### Share on other sites
One way you can do it is to make each rotation a seperate piece, and switch them out when the player presses the rotate button.

##### Share on other sites
The way that you rotate the piece depends on the way you store your pieces. If you use a 2D array to store the pieces, you can rotate them rather easily by shifting the values around manually.

##### Share on other sites
I did it in a funky way. I had a single array with just 4 elements (objects of a class named "block"). Here is how I did it:

enum DIRECTION { C, N, S, E, W, NE, SE, NW, SW, NN, SS, EE, WW };class block{ DIRECTION direction; int xpos; int ypos; int block_color;}; // end block classblock current_piece[4]; // this stores the piece that is currently in playint main_grid[10][20]; // this keeps track of the fallen blocks.

Ok, so you may be wondering why I did it this way. Isn't there a simpler way? I can almost guarantee you there is, for no other reason than the fact that I suck at programming. But nonetheless, I will explain it.

So, the main_grid is just as it looks. It is a 10x20 grid. I think most Tetris games are 10x20, right? It is meant to store the blocks that have already fallen, from past pieces. Once a piece lands, its blocks are saved to this grid.

The current_piece is my array of four block objects. All tetrads have four blocks, so there's not much else to say about it.

The block class keeps track of the different properties of the block: the color of the block (possible values: 1-4, each of which indexes some RGB value that can change throughout the game), its x and y positions with respect to the main game grid, and then the direction of the block with respect to the center of the piece.

Ok so the part you are probably wondering about is the whole "direction" thing. I will get to that in a sec.

Each block has an initial position. There is a function which "creates" a new piece and sets everything into its proper position. Every so often, the piece needs to move down a step, so every so often the game will update the to that effect.

Ok so what if the piece has to rotate? That's where the "direction" bit comes in, because if you'd notice there is no "piece" objects -- the piece is just an array -- and there is no way for the program to know which tetrad the piece is suppose to be (not without some complicated code, anyway), and so its impossible to know where each block should ultimately end up after the rotation when given just the xpos and ypos and color.

The "direction" value is a way for the block to know how it should rotate itself. Each piece has a center block -- that's the "C." This block does not move during the rotation. If you pick up a copy of the standard Gameboy Tetris you'll see that, as each piece rotates, there is always one piece that doesn't move. I'm not sure if the Gameboy Tetris is what you are shooting for, but it was my goal so I went for it.

A block marked as "N" will always by one space above the "C" block. An "E" block will always be one space to the right. An "EE" is two spaces to the right. An "SW" is one piece to the left and one piece down.

These aren't used by the program to determine the position of the block. That's what xpos and ypos are for. However, this value DOES help the program determine where the block should be moved when it rotates because, no matter what sort of tetrad the piece is, a "N" block will always move one space to the right and one space down to become an "E" piece when rotated in the clockwise direction. So the xpos of the piece is +=1 and the ypos is -=1 and the direction is changed to "E." A "C" piece will never move (a "square" tetrad is comprised entirely of "C" pieces). An "EE" piece will move two spaces down and two spaces to the left to become an "SS" piece.
 .. .. NN .. .. .. NW N  NE .. WW W  C  E  EE  .. SW S  SE .. .. .. SS .. ..

Usually I will have a piece called temp_piece[4]. To rotate, I will set temp_piece to equal current_piece. Then, I will rotate temp_piece and test it for collisions with the main_grid (a 0 value on the main grid mean "no block" while a number from 1-4 indicates that a block is extant). If the temp_piece passes the test, then current_piece is set to equal temp_piece and the game moves on.

The rotation function was basically a huge switch(temp_piece[x].direction) with a different case for each type of direction and it would tell the block how to move based on what direction it was currently in.

##### Share on other sites
Wow, i must say that it is brillant. I didn't think that way of that logic, even if i did draw on a paper the way the square move. I will follow what you said, it's look like i will need to store a value for the piece for "E" or "EE" and make a switch to take care of the rotation. For now i'm not certain how i will handle the square ( even if it's coded it's not positive that's it's gonna stay like that ) but i will try to adjust your logic to my code. Thank again.

##### Share on other sites
Expanding on uncle_rico's method, you can always precalculate all your piece rotations (so 1 piece would contain 4 arrays comprising the rotated directions), saving a bunch of cycles, code and effort:

Quote:
 class cPiece{public: enum eOrientation { UP=0, LEFT, DOWN, RIGHT } eCurrentOrientation; enum eRotationDirection { LEFT, RIGHT }; bool Rotate( eRotation rot_dir ); // flips our orientation if possible cBlock *GetBlockMap() const; // returns correct blockmapprivate: cBlock piece_map[3][3][3]; // blockmaps for all orientations};

::Rotate( LEFT|RIGHT ) will collision check, and if piece can rotate will change our eCurrentOrientation member. ::GetBlockMap() returns the correct block map with our current orientation.

Additionally, IIRC, the straight tetroid does not have a focal point, so this method can solve that problem, too.

:stylin:

EDIT: fixed 3-dimensional array

[Edited by - stylin on August 11, 2005 5:19:42 AM]

##### Share on other sites
If I were a better programmer then I would know what stylin was talking about, but since I don't my advice is to just do what he says! Hah.

If you think about it, there are 7 basic pieces. There's the "straight line" piece, a "z" piece, a reverse "z" piece, an "L" piece, a reverse "L" piece, a "T" piece, and a "square" piece.

When the square piece rotates, the new space that each block takes up was once occupied by an adjacent pieces. So, the northwest block will move once to the right, where the northeast block was, and the northeast block will move down once to where the southeast block was. But why bother with all of this? The end result is that the square looks exactly as it did before. It's like trying to rotate a circle. It always looks the same. So, I simply set each of the blocks for a Square Piece to "C". That way, they don't move during the rotation at all.

On the Gameboy Tetris, the line piece doesn't rotate about the exact center like you might expect. This would actually be impossible given the grid-like nature of the game area. So, you just have to choose one of the off-center blocks to be the center piece, like this:
[WW][ W][ C][ E]

Using the rotation logic that I explained, the WW would become NN, the W will become N, the C will stay the same, and the E will become S:
[NN][ N][ C][ S]

It would seem ideal to make the centerbe some point in between the C and N blocks above, but the grid won't allow for it. The result would be a piece that overlaps the grid lines.

Every other piece, besides this line piece and the square, are pretty straight-forward. You won't have to use the NN, SS, WW, or EE for any of the other pieces, and the other pieces will only need on "C", for example:
[NW][ N]    [ C][ E]

The rotation function would indeed be a big switch just like you said. You would just need to nest it inside a for loop so that you can rotate one block at a time.

Or, as was said earlier, you could probably just precalculate each rotation beforehand, although I've never worked out how to do that myself. I'm sure it's a better way to go, and maybe next time I'll try it out.

##### Share on other sites
In my version I got around the weird 4x4 rotations by doing a simple paint-like 90-degree rotation followed by shifting the block down and to the right within its 4x4 sandbox until it touched both edges, resulting in a very consistent and easy to code rotation. Of course, this is a very wasteful way to do this considering all of the necessary compares along an array, but then again it is tetris, and that waste'll never be noticed. [wink]

Makes me wonder what the original GameBoy implementation (code) looked like...

1. 1
Rutin
39
2. 2
3. 3
4. 4
5. 5

• 12
• 17
• 12
• 14
• 9
• ### Forum Statistics

• Total Topics
633358
• Total Posts
3011507
• ### Who's Online (See full list)

There are no registered users currently online

×