想到我开发的第一版俄罗斯方块,处理旋转的代码也是非常粗暴,就是所有方块的旋转都单独写一段代码来处理,而不像现在的,使用一个通用的算法就搞定所有方块的旋转。
01.旋转图形算法
最出名的就是矩阵旋转,看了下介绍和实现流程后,果断放弃了,我相信绝对有超级简单的几行代码就能搞定方块旋转的算法。毕竟我只是旋转90度,根本用不到矩阵里面的各种角度计算。然后,我就寻找到了一段旋转数组的代码,经过几个小时的探索后,成功敲出了属于我这个项目的旋转方块代码:
// 旋转方块
void RotateBlock()
{
// 获取方块宽
int blockWidth = _blockLayer.Size._width;
// 存储旋转后的方块数据
List<MyPoint> rotatedBlockData = new List<MyPoint>();
// 开始旋转
foreach (var item in _blockLayer.ViewData)
{
MyPoint rotated = new MyPoint();
rotated._list = item._line;
rotated._line = blockWidth - item._list - 1;
rotatedBlockData.Add(rotated);
}
// 替换成旋转后的方块数据
_blockLayer.ViewData = rotatedBlockData;
_screenMain.RefreshScreen();
}
添加按键处理代码:
// 按键 - 上方向键
if (Input.GetKeyDown(KeyCode.UpArrow))
{
// 立即旋转一次
RotateBlock();
InvokeRepeating("RotateBlock", 0.2f, 0.2f);
}
if (Input.GetKeyUp(KeyCode.UpArrow))
{
CancelInvoke("RotateBlock");
}
不出意外的话,你可以成功看到方块的旋转效果。顺便提一下,我的方块旋转后都是停靠在左下角的,就是说,旋转后的图形,坐标是没有任何变化的(为了说明这个问题,我打了很多字,后来感觉还不如用图片解释方便):
如图所示,左侧的是我目前的旋转方式,旋转完成后,方块依然是以左下角对齐的。而右侧的旋转方式会导致方块的纵坐标下降。
之所以我使用左侧的方式是因为:屏幕本来就很小,如果因旋转而导致方块被迫下降的话,感觉对玩家不公平,当然,你可以旋转完成之后调整纵坐标,这些都是很灵活的修改的。我主要目的还是为了说明我是如何旋转方块的。
02.旋转算法原理
其实上面代码中,核心代码就是那两行调整坐标的代码:
rotated._list = item._line;
rotated._line = blockWidth - item._list - 1;
我觉得有必要来解释下转换的原理。
第一行代码是计算旋转之后的列号。如上图所示,旋转后的方块(右侧)的第一列(从左往右数)就是旋转前的方块(左侧)的第一行(从下往上数),第二列就是旋转前的方块的第二行。
第二行代码是计算旋转之后的行号。如上图所示,第一、二、三列分别转换为第三、二、一行。可能第一眼看过去,不知道如何找到一个通用的公式来转换,其实很简单:红色点与左侧的偏移为0,旋转后,红色点与顶端的偏移为0;黄色点与左侧的偏移为1,旋转后与顶端的偏移为1;绿色点与左侧偏移为2,旋转后与顶端偏移为2。旋转之后,方块的宽则变成高度,左侧方块的列号 = 方块的宽 - 列偏移,旋转之后,行号 = 方块高 - 行偏移,因为方块高与旋转前的方块宽一样,行偏移与旋转前的列偏移一样,所以公式为:
旋转后的行号 = 方块的宽度 - 列偏移距离
红色点列偏移为0,旋转后,与顶端的偏移就是3 - 0 = 3
黄色点列偏移为1,旋转后,与顶端的偏移就是3 - 1 = 2
绿色点列偏移为2,旋转后,与顶端的偏移就是3 - 2 = 1
当然,这是错误的结果,因为下标是从0开始,所以最终还要再减1,那么最终公式就是:
旋转后的行号 = 方块的宽度 - 列偏移距离 - 1
怎么样,是不是很简单。好了,下一节,来处理旋转的碰撞。
代码链接:https://pan.baidu.com/s/1XJgOGIbBGIeD3_cDwhfUoQ
提取码:uloj
网友评论