绕枢轴旋转坐标? (俄罗斯方块)

发布于 2024-08-05 14:05:43 字数 228 浏览 4 评论 0原文

我正在尝试设计我自己的俄罗斯方块克隆,但遇到了形状旋转的小问题。我有一个表示 10 x 20 游戏网格和单个形状对象的二维数组,这些对象在初始化时包含形状在网格上开始掉落的坐标。例如,当用户向下移动形状时,每个坐标的 y 值都会递减,并且此更改会反映在网格上。

我似乎无法弄清楚使用此实现来处理形状旋转的有效方法。有什么方法可以使用这些围绕指定枢轴的坐标的矩阵吗?

任何建议将不胜感激,

谢谢。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

乖不如嘢 2024-08-12 14:05:43

经典旋转矩阵是否有效,将取决于您要使用的旋转系统。我将使用 SRS 作为示例。

绕原点逆时针旋转的旋转矩阵为:

[0 -1]
[1  0]

现在,假设您有一个坐标列表 [(0, 1), (1, 1), (2, 1), (3, 1)] 表示 I -block 在其初始位置:

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

请注意,我不使用笛卡尔坐标系,而是使用通常的屏幕坐标,从左上角开始。要正确旋转块,首先必须考虑 y 轴的翻转。旋转矩阵则变为:

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

接下来,要绕枢轴点旋转,在旋转之前,您必须移动坐标,使枢轴点成为原点(下面称为 sb )并将它们移回原点旋转后(下面称为 sa):

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

通常您会得到 sb = sa,但对于俄罗斯方块块,枢轴点有时位于两个单元格之间的网格上(对于 I-和 O 块),有时位于单元格的中心(对于所有其他块)。

事实证明,

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

其中 me 是要旋转的块的最大范围(即 2、3 或 4),适用于所有块。总而言之,您会得到:

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

顺时针旋转是类似的,但如果您缓存所有块方向的坐标,您将只需要一个方向。

对于其他旋转系统,移位变量的其他值可能有效,但您可能必须再次移动该块,具体取决于块的当前方向(比较 SRS 旋转 到 I-的DTET 旋转阻止,看看我的意思)。

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).

青春有你 2024-08-12 14:05:43

当然,查找“仿射变换”。但在你的例子中,你得到的正是一个物体以离散角度的四种可能的旋转——没有 70.3° 旋转,它只是 0、90°、180°、270°。那么为什么不预先计算呢?

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?

半岛未凉 2024-08-12 14:05:43

这是经典的线性代数。您正在寻找旋转矩阵,但所有角度都是直角,因此您可以预先计算正弦和余弦。

维基百科:旋转矩阵

要围绕一个点进行旋转,您必须先减去中心值(将该参考点作为中心原点),然后应用矩阵,并将原始中心位置添加回来。

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.

柠北森屋 2024-08-12 14:05:43

我自己也遇到过这个问题,并且我找到了有关该主题的精彩维基百科页面(在“常见轮换”段落中:
https://en.wikipedia.org/wiki/Rotation_matrix#Ambiguities

然后我写了下面的代码非常详细,以便清楚地了解发生了什么。

我希望它有助于更​​好地理解它是如何工作的。

要快速测试它,您可以将其复制/粘贴到此处:
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 "=== === === === === === === === === "

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 "=== === === === === === === === === "
橘寄 2024-08-12 14:05:43

我想你现在已经完成了这个。
我不是程序员,但我记得在大学时做过这件事。每件作品我们只有 4 个不同的物体(具有不同的旋转)。例如,“L”形有 1、2、3、4 块。如果您的活动部件位于 3 中,并且您顺时针旋转,则加载部件 4,再次顺时针旋转并加载部件 1。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文