俄罗斯方块棋子旋转算法
表示和旋转俄罗斯方块游戏棋子的最佳算法(和解释)是什么? 我总是发现片段轮换和表示方案令人困惑。
大多数俄罗斯方块游戏似乎在每次旋转时都使用天真的“重制块数组”:
http://www.codeplex.com/Project/ProjectDirectory.aspx?ProjectSearchText=tetris
但是,有些使用预先构建的编码数字和位移来表示每个部分:
http://www.codeplex.com/wintris
有没有一种方法可以使用数学来做到这一点(不确定这是否适用于基于单元的主板)?
What are the best algorithms (and explanations) for representing and rotating the pieces of a tetris game? I always find the piece rotation and representation schemes confusing.
Most tetris games seem to use a naive "remake the array of blocks" at each rotation:
http://www.codeplex.com/Project/ProjectDirectory.aspx?ProjectSearchText=tetris
However, some use pre-built encoded numbers and bit shifting to represent each piece:
http://www.codeplex.com/wintris
Is there a method to do this using mathematics (not sure that would work on a cell based board)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
您只能通过对其应用数学运算来旋转矩阵。 如果你有一个矩阵,说:
要旋转它,将其乘以它的转置,然后乘以这个矩阵([I]dentity [H]orizontaly [M]irrored):
然后你将得到:
注意:旋转中心将是矩阵的中心,在本例中为 (2,2)。
You can rotate a matrix only by applying mathematical operations to it. If you have a matrix, say:
To rotate it, multiply it by its transpose and then by this matrix ([I]dentity [H]orizontaly [M]irrored):
Then you'll have:
Note: Center of rotation will be the center of the matrix, in this case at (2,2).
表示
表示最小矩阵中的每个部分,其中 1 代表四方体占据的空间,0 代表空的空间。 例子:
旋转公式
插图
Representation
Represent each piece in the minimum matrix where 1's represent spaces occupied by the tetriminoe and 0's represent empty space. Example:
Rotation Formula
Illustration
由于每个形状只有 4 个可能的方向,为什么不使用形状的状态数组,并按 CW 或 CCW 旋转简单地增加或减少形状状态的索引(对索引进行环绕)? 我认为这可能比执行旋转计算等更快。
Since there are only 4 possible orientations for each shape, why not use an array of states for the shape and rotating CW or CCW simply increments or decrements the index of the shape state (with wraparound for the index)? I would think that might be quicker than performing rotation calculations and whatnot.
我从此处的矩阵旋转导出了旋转算法。 总结一下:如果您有组成块的所有单元格的坐标列表,例如 [(0, 1), (1, 1), (2, 1), (3, 1)] 或 [( 1, 0), (0, 1), (1, 1), (2, 1)]:
计算新坐标
您可以使用顺时针旋转和
逆时针旋转来 。
me
是块的最大范围,即 I 块为4
,O 块为2
,O 块为3
> 对于所有其他块。I derived a rotation algorithm from matrix rotations here. To sum it up: If you have a list of coordinates for all cells that make up the block, e.g. [(0, 1), (1, 1), (2, 1), (3, 1)] or [(1, 0), (0, 1), (1, 1), (2, 1)]:
you can calculate the new coordinates using
for clockwise rotation and
for counter-clockwise rotation.
me
is the maximum extent of the block, i.e.4
for I-blocks,2
for O-blocks and3
for all other blocks.如果您在 python 中执行此操作,基于单元格而不是坐标对,则旋转嵌套列表非常简单。
If you're doing this in python, cell-based instead of coordinate pairs it's very simple to rotate a nested list.
如果我们假设四格骨牌的中心方块的坐标 (x0, y0) 保持不变,那么 Java 中其他 3 个方块的旋转将如下所示:
If we assume that the central square of the tetromino has coordinates (x0, y0) which remains unchanged then the rotation of the other 3 squares in Java will look like this:
适用于 3x3 大小的俄罗斯方块
翻转你的作品的 x 和 y
然后交换外列
这就是我有一段时间想出来的
for 3x3 sized tetris pieces
flip x and y of your piece
then swap the outer columns
that's what I figured out some time
我对所有形状中的四个点使用了形状位置和四个坐标集。 由于它位于 2D 空间中,因此您可以轻松地将 2D 旋转矩阵应用于这些点。
这些点是 div,因此它们的 css 类从关闭变为打开。 (这是在清除了上一轮的 css 类之后的结果。)
I have used a shape position and set of four coordinates for the four points in all the shapes. Since it's in 2D space, you can easy apply a 2D rotational matrice to the points.
The points are divs so their css class is turned from off to on. (this is after clearing the css class of where they were last turn.)
如果数组大小为 3*3 ,则逆时针方向旋转它的最简单方法是:
If array size is 3*3 ,than the simplest way to rotate it for example in anti-clockwise direction is:
Python:
Python:
至少在 Ruby 中,您实际上可以使用矩阵。 将您的块形状表示为数组的嵌套数组,例如 [[0,1],[0,2],[0,3]]
但是,我同意对形状进行硬编码是可行的,因为有 7 种形状和 4 种状态每行 = 28 行,而且永远不会超过这个数。
有关这方面的更多信息,请参阅我的博客文章:
https://content.pivotal。 io/blog/the-simplest-thing-that-could-possously-work-in-tetris 以及 https://github.com/andrewfader/Tetronimo
In Ruby, at least, you can actually use matrices. Represent your piece shapes as nested arrays of arrays like [[0,1],[0,2],[0,3]]
However, I agree that hard-coding the shapes is feasible since there are 7 shapes and 4 states for each = 28 lines and it will never be any more than that.
For more on this see my blog post at
https://content.pivotal.io/blog/the-simplest-thing-that-could-possibly-work-in-tetris and a completely working implementation (with minor bugs) at https://github.com/andrewfader/Tetronimo
在 Java 中:
作为 Java 中的单页应用程序的简单俄罗斯方块实现:
https://github.com/vadimv/rsp-tetris
In Java:
A simple Tetris implementation as a single-page application in Java:
https://github.com/vadimv/rsp-tetris
当我试图弄清楚旋转如何适用于我的俄罗斯方块游戏时,这是我在堆栈溢出上发现的第一个问题。 尽管这个问题很老了,但我认为我的输入将帮助其他人尝试通过算法解决这个问题。 首先,我不同意对每个部分进行硬编码和旋转会更容易。 Gamecat的答案是正确的,但我想详细说明一下。 以下是我在 Java 中解决旋转问题的步骤。
对于每个形状,确定其原点在哪里。 我使用此页面中图表上的点来指定我的原点。 请记住,根据您的实现,您可能必须在用户每次移动该块时修改原点。
旋转假设原点位于点 (0,0),因此您必须先平移每个块,然后才能旋转它。 例如,假设您的原点当前位于点 (4, 5)。 这意味着在旋转形状之前,每个块必须在 x 坐标中平移 -4,在 y 坐标中平移 -5,以相对于 (0,0)。
在Java中,典型的坐标平面从左上角的点(0,0)开始,然后向右和向下增加。 为了在我的实现中补偿这一点,我在旋转之前将每个点乘以 -1。
以下是我用来计算逆时针旋转后新的 x 和 y 坐标的公式。 有关这方面的更多信息,我会查看维基百科页面上的旋转矩阵。 x' 和 y' 是新坐标:
x' = x * cos(PI/2) - y * sin(PI/2) 且 y' = x * sin(PI/2) + y * cos(PI/2)
.
对于最后一步,我只是以相反的顺序执行了步骤 2 和 3。 因此,我再次将结果乘以 -1,然后将块平移回其原始坐标。
下面是对我有用的代码(Java),让我了解如何用您的语言执行此操作:
此方法是将您的形状向左旋转所需的全部,结果证明它要小得多(取决于你的语言)而不是为每个形状定义每个旋转。
When I was trying to figure out how rotations would work for my tetris game, this was the first question that I found on stack overflow. Even though this question is old, I think my input will help others trying to figure this out algorithmically. First, I disagree that hard coding each piece and rotation will be easier. Gamecat's answer is correct, but I wanted to elaborate on it. Here are the steps I used to solve the rotation problem in Java.
For each shape, determine where its origin will be. I used the points on the diagram from this page to assign my origin points. Keep in mind that, depending on your implementation, you may have to modify the origin every time the piece is moved by the user.
Rotation assumes the origin is located at point (0,0), so you will have to translate each block before it can be rotated. For example, suppose your origin is currently at point (4, 5). This means that before the shape can be rotated, each block must be translated -4 in the x-coordinate and -5 in the y-coordinate to be relative to (0,0).
In Java, a typical coordinate plane starts with point (0,0) in the upper left most corner and then increases to the right and down. To compensate for this in my implementation, I multiplied each point by -1 before rotation.
Here are the formulae I used to figure out the new x and y coordinate after a counter-clockwise rotation. For more information on this, I would check out the Wikipedia page on Rotation Matrix. x' and y' are the new coordinates:
x' = x * cos(PI/2) - y * sin(PI/2) and y' = x * sin(PI/2) + y * cos(PI/2)
.
For the last step, I just went through steps 2 and 3 in reverse order. So I multiplied my results by -1 again and then translated the blocks back to their original coordinates.
Here is the code that worked for me (in Java) to get an idea of how to do it in your language:
This method is all that is needed to rotate your shape to the left, which turns out to be much smaller (depending on your language) than defining each rotation for every shape.
形状数量有限,所以我会使用固定表格而不进行计算。 这样可以节省时间。
但有旋转算法。
选择一个中心点并旋转 pi/2。
如果一个块从 (1,2) 开始,它会顺时针移动到 (2,-1) 和 (-1,-2) 和 (-1, 2)。
将其应用于每个块并旋转该块。
每个 x 都是前一个 y,每个 y - 前一个 x。 给出以下矩阵:
对于逆时针旋转,请使用:
There is a limited amount of shapes, so I would use a fixed table and no calculation. That saves time.
But there are rotation algorithms.
Chose a centerpoint and rotate pi/2.
If a block of a piece starts at (1,2) it moves clockwise to (2,-1) and (-1,-2) and (-1, 2).
Apply this for each block and the piece is rotated.
Each x is the previous y and each y - the previous x. Which gives the following matrix:
For counterclockwise rotation, use:
这就是我最近在基于 jQuery/CSS 的俄罗斯方块游戏中所做的。
计算出块的中心(用作枢轴点),即块形状的中心。
称之为(px,py)。
组成方块形状的每块砖块都会围绕该点旋转。
对于每个砖块,您可以应用以下计算...
其中每个砖块的宽度和高度为 q,砖块的当前位置(左上角)为 (x1, y1),新砖块位置为 (x2, y2) :
反向旋转:
此计算基于 2D 仿射矩阵变换。
如果您对我是如何做到这一点感兴趣,请告诉我。
This is how I did it recently in a jQuery/CSS based tetris game.
Work out the centre of the block (to be used as a pivot point), i.e. the centre of the block shape.
Call that (px, py).
Each brick that makes up the block shape will rotate around that point.
For each brick, you can apply the following calculation...
Where each brick's width and height is q, the brick's current location (of the upper left corner) is (x1, y1) and the new brick location is (x2, y2):
To rotate the opposite direction:
This calculation is based on a 2D affine matrix transformation.
If you are interested in how I got to this let me know.
就我个人而言,我总是用手来表示旋转——形状很少,这样很容易编码。 基本上我有(作为伪代码)
至少在概念上 - 直接形状的多维点数组也可以做到这一点:)
Personally I've always just represented the rotations by hand - with very few shapes, it's easy to code that way. Basically I had (as pseudo-code)
At least conceptually - a multi-dimensional array of points directly in shape would do the trick too :)