Jump to content

  • Log In with Google      Sign In   
  • Create Account


Tetris Rotation Problem


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
14 replies to this topic

#1 Zido_Z   Members   -  Reputation: 356

Like
0Likes
Like

Posted 13 September 2012 - 03:32 PM

So, I'm programming Tetris at the moment. I researched around on how people approached their design of Tetris. That's when I came upon this article. The one part I got stuck on was the explanation of rotating a piece. It reads:

Next, we compute the new location. Our goal is to keep the center of the falling piece constant (or, given that this is not possible if we have an even number of rows or columns, to keep the center as constant as possible). Keeping the center of the falling piece constant during rotation is the most difficult part of Tetris, so read this part very carefully (though that is always good advice!). Besides making rotation more intuitive, we want to keep the center constant so that if we rotate around and around, the center does not "drift" -- a full 360 degree turn should bring us back to where we started. To meet these conditions, we observe that we just need to adjust the left column and top row of the falling piece by subtracting half of the change in the size of each dimension that results from each turn, where the change in the size of each dimension equals the difference between the number of rows and columns (though you have to think about whether this difference should be positive or negative). Read and re-read the preceding paragraph. Draw pictures. Make sense out of it. When you finally convert it into Java, you will find there are two simple lines that make rotation-about-a-fixed-center work:
fallingPieceRow -= <something>;
fallingPieceCol -= <something else>;


Doing as he said, I've been writing and drawing stuff for an hour, and I still haven't figured out what he means. Is he referring to subtracting the half of "change in size" from the top left most cell of each piece to keep the center orientated throughout rotations? I'm having trouble wrapping my head around what he meant.

Sponsor:

#2 phil_t   Crossbones+   -  Reputation: 3210

Like
0Likes
Like

Posted 14 September 2012 - 12:09 AM

I don't understand it either. I'm not sure why it needs to be that complicated. Just pick one square of the piece to be the center of rotation, and go from that.

#3 DoubleDouble   Members   -  Reputation: 107

Like
1Likes
Like

Posted 14 September 2012 - 02:38 AM

He is poorly explaining that section.
When he says, "subtract half the change in size of each dimension that results from each turn" He means...

For my example, imagine the 'T' piece.
" the size of each dimension"- for the T piece, it is 3 squares across (the x dimension) and two squares up-and-down (the y dimension)

If you were to rotate the T piece clockwise, so the part currently sticking down is sticking out to the left, it would be flipped to 2 squares across (x) and 3 squares up-and-down (y)

The change in size for each dimension is then 3-2=1 (X dimension)
2-3 = -1(Y dimension)
half the change in size: 0.5(X Dimension)
-0.5(Y Dimension)

At least, thats what it seems like he's saying to me. I'm actually not sure how that helps, and like he says, " you have to think about whether this difference should be positive or negative."

#4 slicer4ever   Crossbones+   -  Reputation: 3220

Like
0Likes
Like

Posted 14 September 2012 - 08:05 AM

I don't understand it either. I'm not sure why it needs to be that complicated. Just pick one square of the piece to be the center of rotation, and go from that.


This is what i did when i made tetris, i played some games of tetris, and just watched for what square was being used for rotations, it's pretty straight-forward imo.
Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

#5 Zido_Z   Members   -  Reputation: 356

Like
0Likes
Like

Posted 14 September 2012 - 08:13 PM

I assumed there was some logic behind it, mainly because what happens when there's a variable set of rows and columns for each piece, aka custom pieces. Normally, it would be easy to say "choose this center block," but I figured he was explaining it because when you do rotate a piece, it ends up in the same spot, but not using like a single cell of the array.

#6 Dragonsoulj   Crossbones+   -  Reputation: 2009

Like
2Likes
Like

Posted 14 September 2012 - 09:09 PM

I preferred a source that described the game itself. Search for section 5.3 on this page: Link It helped me a lot.

#7 Zido_Z   Members   -  Reputation: 356

Like
0Likes
Like

Posted 16 September 2012 - 02:05 AM

I preferred a source that described the game itself. Search for section 5.3 on this page: Link It helped me a lot.

This is actually very helpful. Thank you!

#8 Goran Milovanovic   Members   -  Reputation: 1103

Like
6Likes
Like

Posted 19 September 2012 - 10:51 PM

I made a quick video tutorial that explains how to rotate a tetris block with matrices. I hope you find it hepful:

http://www.youtube.com/watch?v=Atlr5vvdchY

Here's the Python code for the demo program (requires the pslab library):

[source lang="python"]# Block rotation demo - Goran Milovanovic, 2012## Left click on empty cells to populate with blue# Left click on blue cells to set pivot# Right click to eraseimport pslabimport timeclass Cell: slab_stamp = pslab.Slab(62, 62) slab_stamp.fill(0xFFFFFF) slab_empty = pslab.Slab(64, 64) slab_stamp.burnInto(slab_empty, 1, 1) slab_blue = pslab.Slab(64, 64) slab_stamp.fill(0x0055FF) slab_stamp.burnInto(slab_blue, 1, 1) slab_green = pslab.Slab(64, 64) slab_stamp.fill(0x00FF55) slab_stamp.burnInto(slab_green, 1, 1) def __init__(self, idx_row, idx_col): self.pos = (idx_row, idx_col) self.slab = self.slab_empty def setSlab(self, slab): self.slab = slab def getSlab(self): return self.slab def getPosBoard(self): return self.pos def getPosScreen(self): return (self.slab.getWidth() * self.pos[1], self.slab.getHeight() * self.pos[0])class Board(list): def __init__(self): self.dim = (8, 8) super().__init__( ( [ Cell(i, j) for j in range(self.dim[1]) ] for i in range(self.dim[0]) ) ) self.pivot = None def setPivot(self, cell): if cell: cell.setSlab(Cell.slab_green) if self.pivot: self.pivot.setSlab(Cell.slab_blue) self.pivot = cell def getPivot(self): return self.pivot def getBlueCells(self): active = [] for row in self: for cell in row: if cell.getSlab() == Cell.slab_blue: active.append(cell) return active def burnInto(self, slab_dest): for row in self: for cell in row: slab = cell.getSlab() slab.burnInto(slab_dest, *cell.getPosScreen()) def posToIdx(self, sx, sy): slab = board[0][0].getSlab() return (sy // slab.getHeight(), sx // slab.getWidth()) def posValid(self, pos_board): for i, n in enumerate(pos_board): if n > self.dim[i] - 1 or n < 0: return False return Truedef matMulVec(mat, vec): vec_new = [] for row in mat: vec_new.append(sum( (a * b for a, b in zip(row, vec) ) ) ) return vec_new if __name__ == "__main__": window = pslab.Window(512, 512) window.setTitle("Block Rot") window.fill(0xEEEEEE) board = Board() board.burnInto(window) window.update() mat_rot = ( (0, -1), (1, 0) ) mouse = window.mouse kb = window.keyboard while True: window.processEvents() lclick = mouse.btnHit("lmb") rclick = mouse.btnHit("rmb") if lclick or rclick: mx, my = mouse.getPosition() i_row, i_col = board.posToIdx(mx, my) cell = board[i_row][i_col] slab = cell.getSlab() if lclick: if slab == Cell.slab_blue: board.setPivot(cell) elif slab == Cell.slab_empty: cell.setSlab(Cell.slab_blue) else: if cell == board.getPivot(): board.setPivot(None) cell.setSlab(Cell.slab_empty) board.burnInto(window) window.update() if kb.keyHit("space") and board.getPivot(): blue_cells = board.getBlueCells() vecs = (cell.getPosBoard() for cell in blue_cells) for cell in blue_cells: cell.setSlab(Cell.slab_empty) vec_p = board.getPivot().getPosBoard() vecs_rel = ((a - b for a, b in zip(vec, vec_p)) for vec in vecs) vecs_rel_rot = (matMulVec(mat_rot, list(vec)) for vec in vecs_rel) vecs_new = ([a + b for a, b in zip(vec_p, vec)] for vec in vecs_rel_rot) for vec in vecs_new: if board.posValid(vec): cell = board[vec[0]][vec[1]] cell.setSlab(Cell.slab_blue) board.burnInto(window) window.update() if kb.keyHit("esc"): break time.sleep(1/30)[/source]

+---------------------------------------------------------------------+

| Need a programmer?        ->   http://www.nilunder.com/protoblend   |

| Want to become one?       ->   http://www.nilunder.com/tutoring     |
| Game Dev video tutorials  ->   http://www.youtube.com/goranmilovano |
+---------------------------------------------------------------------+

#9 stillLearning()   Members   -  Reputation: 212

Like
0Likes
Like

Posted 21 September 2012 - 06:01 AM

I made a quick video tutorial that explains how to rotate a tetris block with matrices. I hope you find it hepful:

I recovered my password and spent lots of time trying to retrieve my old account here just to say that that video tutorial of yours is really well done and helpful! GJ!

If you don't understand the stuff written here, please sharpen your C++ skills.


#10 Pointer2APointer   Members   -  Reputation: 283

Like
0Likes
Like

Posted 21 September 2012 - 03:19 PM

x = x*cos(angle) - y*sin(angle);
----------------------------------------
y = x*sin(angle) + y*cos(angle);

It's pretty hard for a lot of people because it involves Algebra, and we all know that many people prefer to only touch Algebra with a ten foot long stick.

I'll try and explain the situation as best as I can using C++ and SDL as an example, but the problem is the same in any library/language:

First, you might want to try and center the X and Y coordinates of the focus block(the block that's currently falling and you're moving):

int Xcenter;
int Ycenter;

Next, you can try and implement a median (the distance from the center of the focus block to its sides ) like this:

Xcenter -= MEDIAN * 2;
Xcenter += MEDIAN * 2;
Ycenter += MEDIAN * 2;

Then, you can use a coordinate variable (e.g. int x, int y, int x1, int y1, etc.) to call a function (accessor) to return the center of the square, and position it at its origin:

x1 = Xcenter;
y1 = Ycenter;

Then, perform the rotation like follows:

x2 = - y1;
y2 = x1;

Make the necessary adjustments to your control, engine, etc. to change the image in memory of the rotation angle by the 90 degrees or -90 degrees as necessary, and you can get your original location like:

x2 = Xcenter;
y2 = Ycenter;

Of course, there's a bit more to it than just that. You can't expect to rotate an L-block without pre-checking to see if there's a collision at the position, and without not knowing the positions in any sense, or else you'd expect a creepy little bug.

But you said rotation was your problem. The solution I enlisted shows you how to fix a median from a centered image, and then rotate negative or positive, and move around the center of the origin.

Of course, again, someone not being so sufficient in math would probably gain very little from this.

But it's basically a rotation of four 90 degree angles. Whatever you ultimately can put together is up to each person.

If it works, it works. Those are the basic steps. Cleaning up messy code, working on memory use, and fixing small bugs can done progessively through the production, but testing a well-working program always should be satisfactory.

Edited by Pointer2APointer, 22 September 2012 - 02:09 PM.

Yes, this is red text.

#11 Goran Milovanovic   Members   -  Reputation: 1103

Like
0Likes
Like

Posted 23 September 2012 - 12:59 AM

I recovered my password and spent lots of time trying to retrieve my old account here just to say that that video tutorial of yours is really well done and helpful! GJ!


Heh, thanks. Posted Image

+---------------------------------------------------------------------+

| Need a programmer?        ->   http://www.nilunder.com/protoblend   |

| Want to become one?       ->   http://www.nilunder.com/tutoring     |
| Game Dev video tutorials  ->   http://www.youtube.com/goranmilovano |
+---------------------------------------------------------------------+

#12 Zido_Z   Members   -  Reputation: 356

Like
0Likes
Like

Posted 30 September 2012 - 10:53 PM

I made a quick video tutorial that explains how to rotate a tetris block with matrices. I hope you find it hepful:

http://www.youtube.com/watch?v=Atlr5vvdchY

Sorry for getting to this late. But that was very informative. That's exactly what I needed. I'll get back to you guys on my progress.

@pointer: Your solution works, too. It's mostly helps without having to do an exception case of if the block is a 2 x 2 square, then there won't be a rotation at all. Visual, anyway.

Edited by Zido_Z, 30 September 2012 - 10:54 PM.


#13 LorenzoGatti   Crossbones+   -  Reputation: 2526

Like
0Likes
Like

Posted 02 October 2012 - 07:23 AM

I preferred a source that described the game itself. Search for section 5.3 on this page: Link It helped me a lot.

Indeed. Rotating Tetris pieces doesn't need "general" algorithms, only a table of how each actual piece rotates. It is the heart of the game, and it has to be perfect: for example, if rotating an O piece, an horizontal I piece twice, or a S,Z,L,J,T piece four times in the same direction shifts it left or right we are playing a major variant, not standard Tetris.

Transform matrices might be a good idea (depending on the game engine architecture in use), but they are only useful to implement the desired piece moves, not to design them.
Produci, consuma, crepa

#14 Dragonsoulj   Crossbones+   -  Reputation: 2009

Like
0Likes
Like

Posted 02 October 2012 - 09:16 AM

Indeed. Rotating Tetris pieces doesn't need "general" algorithms, only a table of how each actual piece rotates. It is the heart of the game, and it has to be perfect: for example, if rotating an O piece, an horizontal I piece twice, or a S,Z,L,J,T piece four times in the same direction shifts it left or right we are playing a major variant, not standard Tetris.

Transform matrices might be a good idea (depending on the game engine architecture in use), but they are only useful to implement the desired piece moves, not to design them.

Part of my reason for using it was to lay out all the rules and moves and allow me to come up with how I wanted to implement them. The state space is small enough you could just save each rotation and move between them, using checks to see if the new move would be possible or not.

#15 Mekuri   Members   -  Reputation: 299

Like
0Likes
Like

Posted 02 October 2012 - 09:36 AM

I recently challenged myself to make a tetris game in one day, using XNA. I too spend a lot of time trying to figure out how to rotate the pieces, but I came to the conclusion that it was overkill for such a simple game. I went with hardcoding each possible rotation for the pieces, which isn't that much (Four rotations for L, J and T, Two for S, Z and I, and none for the O).

If you want to calculate rotations because you want to learn how to, it's a good idea- If not, I would consider it overkill. Posted Image

Check out the game I am making here - http://www.youtube.com/user/NasarethMekuri





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS