在运行时旋转俄罗斯方块

Posted

技术标签:

【中文标题】在运行时旋转俄罗斯方块【英文标题】:Rotate tetris blocks at runtime 【发布时间】:2011-10-28 17:31:18 【问题描述】:

我有一个类tetronimo(一个俄罗斯方块块),它有四个QRect 类型(分别命名为firstsecondthirdfourth)。我使用build_tetronimo_L 类型函数绘制每个tetronimo。

这些在某个方向上构建了 tetronimo,但就像在俄罗斯方块中你应该能够旋转 tetronimo 一样,我试图通过旋转 tetronimo 的每个单独的正方形来旋转 tetronimo。

我发现以下公式适用于特定正方形的每个 (x, y) 坐标。

newx = cos(angle) * oldx - sin(angle) * oldy

newy = sin(angle) * oldx + cos(angle) * oldy

现在,Qt 的 QRect 类型似乎只有一个 setCoords 函数,它采用 top-leftbottom-right 的 (x, y) 坐标 相应正方形的点。

我在这里有一个例子(它似乎不会产生正确的结果)旋转我的 tetronimo 中的前两个方块。

谁能告诉我应该如何使用运行时旋转计算正确旋转这些正方形?

void tetromino::rotate(double angle) // angle in degrees

    std::map<std::string, rect_coords> coords = get_coordinates();
        // FIRST SQUARE
    rect_coords first_coords = coords["first"];

    //top left x and y
    int newx_first_tl = (cos(to_radians(angle)) * first_coords.top_left_x) - (sin(to_radians(angle)) * first_coords.top_left_y);
    int newy_first_tl = (sin(to_radians(angle)) * first_coords.top_left_x) + (cos(to_radians(angle)) * first_coords.top_left_y);

    //bottom right x and y
    int newx_first_bl = (cos(to_radians(angle)) * first_coords.bottom_right_x) - (sin(to_radians(angle)) * first_coords.bottom_right_y);
    int newy_first_bl = (cos(to_radians(angle)) * first_coords.bottom_right_x) + (sin(to_radians(angle)) * first_coords.bottom_right_y);
    
        //CHANGE COORDINATES
    first->setCoords( newx_first_tl, newy_first_tl, newx_first_tl + tetro_size,newy_first_tl - tetro_size);
    
        
        //SECOND SQUARE
    rect_coords second_coords = coords["second"];

    int newx_second_tl = (cos(to_radians(angle)) * second_coords.top_left_x) - (sin(to_radians(angle)) * second_coords.top_left_y);
    int newy_second_tl = (sin(to_radians(angle)) * second_coords.top_left_x) + (cos(to_radians(angle)) * second_coords.top_left_y);

        //CHANGE COORDINATES 
    second->setCoords(newx_second_tl, newy_second_tl, newx_second_tl - tetro_size, newy_second_tl + tetro_size);

firstsecondQRect 类型。 rect_coords 只是一个 struct,其中包含四个 ints,用于存储正方形的坐标。

第一个平方和第二个平方的计算是不同的,因为我正在玩弄试图弄明白。

希望有人能帮我解决这个问题?

(是的,我可以做到这一点更简单,但我正在尝试从中学习)

【问题讨论】:

【参考方案1】:

这似乎更像是一道数学题,而不是编程题。只需插入像 90 度这样的角度值来解决这个问题。对于 90 度,点 (x,y) 映射到 (-y, x)。您可能不想围绕原点旋转,而是围绕某个枢轴点 c.x, c.y。为此,您需要先翻译,然后旋转,然后再翻译回来:

(x,y) := (x-c.x, y-c.y) // translate into coo system w/ origin at c
(x,y) := (-y, x)        // rotate
(x,y) := (x+c.x, y+c.y) // translate into original coo system

【讨论】:

【参考方案2】:

在旋转之前,您必须先平移,以使该部分位于原点的中心:

    将居中的块翻译成0, 0 旋转方块 再次将块的中心转换为x, y

如果你旋转而不平移,你将始终围绕0, 0 旋转,但由于块未居中,它将围绕中心旋转。使你的块居中非常简单:

    对于每个点,计算XY 的中位数,我们称之为m 所有点的坐标减去m.Xm.Y 旋转 再次将m.Xm.Y 添加到积分。

当然你可以使用线性代数和vector * matrix 乘法,但可能太多了:)


翻译

假设我们有一个坐标为A(3,5) B(10,15) 的线段。 如果你想围绕它的中心旋转它,我们首先将它翻译到我们的原点。让我们计算mxmy

mx = (10 - 3) / 2
my = (15 - 5) / 2

现在我们计算点 A1B1 平移线段,使其以原点为中心:

A1(A.X - mx, A.Y - my)
B1(B.X - mx, B.Y - my)

现在我们可以执行A1B1 的轮换(你知道怎么做的)。 然后我们又要翻译到原来的位置:

A = (rotatedA1.X + mx, rotatedA1.y + my)
B = (rotatedB1.X + mx, rotatedB1.y + my)

如果您拥有n 点而不是两个点,那么您当然可以为n 点做所有事情。

【讨论】:

不确定“将块中心转换为 0,0”是什么意思?【参考方案3】:

您可以使用 Qt Graphics View 为您完成所有几何计算。

或者您只是想学习基本的线性几何变换?那么阅读数学教科书可能比编码更合适。

【讨论】:

我想学习后者,前者是个好东西,但我不会学习它是如何工作的。 你需要读几何书,画图(用铅笔)来理解事物,做数学练习......同时编码会分散你的注意力,你需要先感受一下(简单的)数学。

以上是关于在运行时旋转俄罗斯方块的主要内容,如果未能解决你的问题,请参考以下文章

java如何用图形界面显示二维数组俄罗斯方块

如何制作俄罗斯方块克隆?

Tetris(俄罗斯方块)

Tetris(俄罗斯方块)

qt5实现俄罗斯方块(详细注释)

Android 安卓原生UI实现游戏《俄罗斯方块》,算法太多,把我写崩溃了,附源码