围绕中心点旋转坐标系?(俄罗斯方块)

4
我正在尝试设计自己的俄罗斯方块克隆版,但在形状旋转方面遇到了一些问题。我有一个二维数组表示10x20游戏网格和单个形状对象,当初始化时包含形状将从哪个位置开始下落的坐标。例如,当用户向下移动形状时,每个坐标的y值都会减少,并且这种变化会反映在网格上。
我似乎找不到一种有效的方法来处理使用此实现的形状旋转。是否有任何方法可以使用矩阵围绕指定的中心点旋转这些坐标?
任何建议都将不胜感激,
谢谢。
5个回答

6
如果使用传统的旋转矩阵取决于您想要使用的旋转系统。我将以SRS为例。
逆时针绕原点旋转的旋转矩阵为:
[0 -1]
[1  0]

现在,假设你有一个坐标列表[(0,1)、(1,1)、(2,1)、(3,1)],代表I型方块的初始位置:
 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 rotationDTET rotation的I块进行比较,以了解我的意思)。


5
当然,可以查找“仿射变换”。但在您的情况下,您拥有的是物体以离散角度旋转的四个可能方向 -- 没有70.3°的旋转,只有0°、90°、180°和270°。那么为什么不预先计算呢?

3
此外,任何“合适”的旋转都会难以将方块定位在合适的网格边界上。对于一组典型的俄罗斯方块,我会为每个方块硬编码它们的4种旋转方式。 - Kylotan
或者,如果必须按过程执行,您可以通过对x、y坐标进行简单的交换和否定来获得直角旋转 - 在纸上工作并且您会发现它很容易。 - Crashworks
同时,要注意棋子在棋盘边缘旋转的情况。在某些情况下,你需要将棋子移回棋盘上。对于硬编码和算法,评分加一。 - Flavius

1

这是经典的线性代数问题。你需要找到一个旋转矩阵,只不过所有的角度都是直角,所以可以预先计算正弦和余弦。

维基百科:旋转矩阵

如果要围绕某个点旋转,则必须首先减去中心值(使该参考点成为中心原点),然后应用矩阵,并添加回原始中心位置。


1

我自己也遇到了这个问题,后来在维基百科上找到了一个很棒的页面(在“常见旋转”段落中:
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 "=== === === === === === === === === "

0

我假设你现在已经完成了这个任务。

虽然我不是程序员,但我记得在大学时也做过类似的东西。我们只需要为每个方块设计四个不同的对象(带有不同的旋转)。例如,“L”形状有1、2、3、4四个部分。如果你当前的方块是第3个部分,并且你顺时针旋转,则加载第4个部分,再次顺时针旋转并加载第1个部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接