Rotating cordinates around pivot? (tetris)
Asked Answered
G

5

4

I'm attempting to design my very own tetris clone but have run into a little problem with shape rotations. I have a 2 dimensional array representing a 10 x 20 game grid and individual shape objects which when initialised contain coordinates of where on the grid the shape will start falling from. So for example, when the user moves the shape down each coordinate's y value gets decremented and this change is reflected on the grid.

What I can't seem to figure out is an efficient way to handle shape rotations using this implementation. Is there any way to maybe use a matrix these coordinates around a designated pivot?

Any suggestions will be greatly appreciated,

Thank you.

Gigahertz answered 22/9, 2009 at 0:46 Comment(0)
C
6

If classic rotation matrices work, will depend on the rotation system you want to use. I will use SRS as an example.

The rotation matrix for counter-clockwise rotation around the origin is:

[0 -1]
[1  0]

Now, suppose you have a list of coordinates [(0, 1), (1, 1), (2, 1), (3, 1)] representing the I-block in its initial position:

 0123
0....
1####
2....
3....

Note that I don't use a cartesian coordinate system, but the usual screen coordinates, starting in the top left. To rotate the block properly, you first have to account for the flip of the y-axis. The rotation matrix then becomes:

[ 0 1]  ->  x_new = y_old
[-1 0]  ->  y_new = -x_old

Next, to rotate around a pivot-point, before rotating, you have to shift the coordinates so that the pivot-point becomes the origin (called sb below) and shift them back after rotating (called sa below):

x_new = sa_x + (y_old - sb_x)
y_new = sa_y - (x_old - sb_y)

Normally you would have sb = sa, but for tetris blocks the pivot-point is sometimes on the grid between two cells (for I- and O-blocks) and sometimes at the center of a cell (for all other blocks).

It turns out that

sa_x = 0
sb_x = 0
sa_y = 1
sb_y = me - 2

where me is the maximum extent (i.e. 2, 3, or 4) of the block to rotate, works for all blocks. So to sum up, you get:

x_new = y_old
y_new = 1 - (x_old - (me - 2))

Clockwise rotation is similar, but if you cache the coordinates for all for block orientations you will only need one direction.

For other rotation systems other values of the shift variables might work, but you might have to shift the piece again, depending on the current orientation of the block (compare SRS rotation to DTET rotation of the I-block, to see what I mean).

Catlett answered 3/1, 2010 at 22:4 Comment(0)
A
5

Sure, look up "affine transform". But in your case what you've got is exactly four possible rotations of an object in discrete angles -- there's no 70.3° rotation, it's just 0, 90°, 180°, 270°. So why not precompute?

Authorized answered 22/9, 2009 at 0:49 Comment(3)
Furthermore, any 'proper' rotation will have trouble locating the blocks on proper grid boundaries. For a typical set of Tetris pieces I'd just hard-code the 4 rotations for each of the pieces.Ruse
Or, if you must do it procedurally, you can get right-angle rotations through simple swaps and negations on x,y coordinates -- work it out on paper and you'll see it's easy.Authorized
Also take care about rotations occuring while the piece is at the edge of the board. Under some circumstances, you will have to move the piece back into the table. +1 for hard-coding, as well for the algorithm.Varus
W
1

This is classic linear algebra. You're looking for a rotation matrix, except all your angles are right angles so you can precalculate the sines and cosines.

Wikipedia: Rotation matrix

To do it around a point, you have to subtract the center value first (making that reference point the center origin) then apply the matrix, and add the original center position back.

Woll answered 22/9, 2009 at 1:33 Comment(0)
W
1

I've had this problem myself and I've found the great wikipedia page on the subject (in "Common rotations" paragraph:
https://en.wikipedia.org/wiki/Rotation_matrix#Ambiguities

Then I wrote the following code, super verbose in order to have a clear understanding of what is going on.

I hope that it can be useful to better understand how this works.

To quickly test it you can copy / paste it here:
http://www.codeskulptor.org/

triangle = [[0,0],[5,0],[5,2]]
coordinates_a = triangle[0]
coordinates_b = triangle[1]
coordinates_c = triangle[2]

def rotate90ccw(coordinates):
    print "Start coordinates:"
    print coordinates
    old_x = coordinates[0]
    old_y = coordinates[1]
# Here we apply the matrix coming from Wikipedia
# for 90 ccw it looks like:
# 0,-1
# 1,0
# What does this mean?
#
# Basically this is how the calculation of the new_x and new_y is happening:
# new_x = (0)(old_x)+(-1)(old_y)
# new_y = (1)(old_x)+(0)(old_y)
#
# If you check the lonely numbers between parenthesis the Wikipedia matrix's numbers finally start making sense.
# All the rest is standard formula, the same behaviour will apply to other rotations
    new_x = -old_y
    new_y = old_x
    print "End coordinates:"
    print [new_x, new_y]

def rotate180ccw(coordinates):
    print "Start coordinates:"
    print coordinates
    old_x = coordinates[0]
    old_y = coordinates[1] 
    new_x = -old_x
    new_y = -old_y
    print "End coordinates:"
    print [new_x, new_y]

def rotate270ccw(coordinates):
    print "Start coordinates:"
    print coordinates
    old_x = coordinates[0]
    old_y = coordinates[1]  
    new_x = -old_x
    new_y = -old_y
    print "End coordinates:"
    print [new_x, new_y]

print "Let's rotate point A 90 degrees ccw:"
rotate90ccw(coordinates_a)
print "Let's rotate point B 90 degrees ccw:"
rotate90ccw(coordinates_b)
print "Let's rotate point C 90 degrees ccw:"
rotate90ccw(coordinates_c)
print "=== === === === === === === === === "
print "Let's rotate point A 180 degrees ccw:"
rotate180ccw(coordinates_a)
print "Let's rotate point B 180 degrees ccw:"
rotate180ccw(coordinates_b)
print "Let's rotate point C 180 degrees ccw:"
rotate180ccw(coordinates_c)
print "=== === === === === === === === === "
print "Let's rotate point A 270 degrees ccw:"
rotate270ccw(coordinates_a)
print "Let's rotate point B 270 degrees ccw:"
rotate270ccw(coordinates_b)
print "Let's rotate point C 270 degrees ccw:"
rotate270ccw(coordinates_c)
print "=== === === === === === === === === "
Whiz answered 14/3, 2017 at 15:4 Comment(0)
L
0

I assume you have finished this by now. I’m not a programmer but I do remember doing this a Uni. We just had 4 different objects (with different rotations) for each piece. Eg the “L” shape has piece 1,2,3,4. If your active piece in 3 and you rotate clockwise then you load piece 4, rotate clockwise again and load piece 1.

Literally answered 5/2, 2010 at 0:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.