易码技术论坛

 找回密码
 加入易码
搜索
查看: 3562|回复: 14

[教程] 用位运算来处理俄罗斯方块

[复制链接]
发表于 2008-4-6 09:45:02 | 显示全部楼层 |阅读模式
前些天,我把C语言的<位运算>一章又详细的研究了一下,然后想了一下要怎么把它合理的利用在文曲星上,突然间,想到了俄罗斯方块这个游戏,想到大量用位运算来编写游戏,没想到速度快了不少.下面我就来讲一下我的思路.

一、首先我们要确定的是方块的显示区域:常规的俄罗斯方块在屏幕上显示的是一个10*20点的长方形。在程序中,常规的表示方法是用一组二维数组来存放这些方块数据。那么我后来想了一下,如果我们把方块显示区域中的所有点都看作是一个变量中的某一位上的数据,那么上面的这个矩形区域我们用20个int型变量就能存下了。而且我们还可以把一个int型数据多出的六个位分别放在屏幕两边显示区之外,这些数据在屏幕上不显示出来,但在程序内部去能读到,其功能后是,当判断到这里时,始终是有数据的,我们就不用去判断是否到了边尽。由于方块是从屏幕顶端开始下落的,为了方便处理,我们把屏幕最顶端在显示区域外再加三层,最后再在最下边再加一层,功能也是不用判断是否到了最下边的边尽。那么我们就可以确定一个拥有24个元素的int型数组。这时整个方块处理区域就如下图所示:
jt.JPG
所有的方块将在空白处进行移动,而红色区域为屏幕能显示到的区域。

二、我们再来确定一下方块的表示方法:我们可以把任何一个方块都视为一个4*4点的方块阵,如图:
box.JPG
像这样的方块矩阵,我们一般是用一个二维数组为存放,但我现在不能这么想了!我们可以用四个int型的变量来存放。为什么要用int型而不用char型呢?因为虽然一个方块的宽度为4,但为了在程序中方便处理,这里我们就以方块处理区域的数据类型使用相同的就行了。

三、方块处理区正在下落的方块的处理方式:一个方块只有4*4,那么我们这里用四个int型的变量来存在一个方块,其中这四个int型变量分别存放方块的每一行,我们再定义一个char floor来表示当前方块处于方块处理区域的哪个高度。再定义一个char move来表示方块处于方块处理区域的左右位置。其实是当前方块左边的bit位序号。当方块出现在方块处理区域时,位置最初是在正中的,那么这个方块的占用的是一个int型变量的bit6~bit9这四个位。那么这一个方块在这四个变量中的初始情况如下图所示:
复件 jt.JPG

四、方块的下落与移动:当方块下落时,直接将表示高度的变量自增一就行了,而当方块向左移动时,那就把表示这个方块的四个变量的数据整体左移一位,向右移动时就把数据右移一位。而方块旋转时,为了方便处理,我们事先把这些方块的数据先作好并存放在一个变量里,如:
int data[方块类型][方块的方向][方块的行];
像上面的这个三维数组中,方块类型可以自定义,标准的俄罗斯方块只有七种类型。方块的方向都有四个方向,像在文曲星上处理速度不是太快的情况下,我们完全可以自己把四个方向的数据全部制作出来。方块的行,一个方块有四行,上面已经说过了。那么:data[6][1][0]~data[6][1][3]就表示第七种方块的第二个方向的方块了。我们在制作这些数据时要注意的是:保持方块数据处于int型变量的bibit6~bit9,以使方块处于初始位置上。当旋转时我们直接使data的第二个下标进行自增一的操作。当大于3时再回复到0就行了。

五、方块的屏幕显示:上面的数据我们已经想好了,但是要怎么用来显示图片呢?下面我们来研究一下。方块处理区域的方块始终会在一个int型变量的bit3~bit12这十位当中的四个连续位。我们在上面已经提到了,要用一个move变量来记录方块的比特位,假设move的值为7,那么我们就可以先把数值1向左移7位,再和记录方块的int型变量进行位与,如果位与后的值等于1向左移7位后的值,那表示当前位是有方块的,否则表示这里没有方块。说到这里,有些星迷可能要问,明明用数组很简单的,干吗要用位运算弄得这么抽象复杂呢?想知道为什么,那就接着向下看。

六、方块数据的判断:说了半天,为什么要用位来表示方块数据呢?然后这里就是关键了。当方块向下移动时,我们把当前正在下落的方块的数据与方块处理区的数据进行判断,假设方块现在整体下移一行,现在我们把这个方块从下到上的四个行的数据分别与对应的方块处理区域的四个行的数据进行位与,如果位与后的值为非零值,那就表示某个地方有方块重合,则表示方块已经不能移动了。否则表示方块可以向下移动。对于左移与右移也一样,先将当前下落的方块数据整体左移一位或右移一位后与对应的方块处理区域的数据进行位于,如果值为0就可以移动,否则不能移动。旋转也是如此,如果旋转后与当前行的方块处理区域的数据位与后的值为0就表示可以旋转,否则不能旋转。看到了吧,对于判断简直太简单真观了,只要进行位与的运算就可以了。我们知道,俄罗斯方块的核心就是进行方块移动或下落时的判断。使用数组表示的方块在判断时太麻烦,而且影响速度。而用位运算,在显示图片时可能会慢一些,但在判断这一环节就会快好几倍。所以游戏速度大大地提高了。

七、下落中的方块数据向方块处理区域进行数据传送:当一个方块落到最下面不能再向下移动时,那这个方块的数据会自动传送到方块处理区域当中去。其实也很简单。把下落中的方块数据与方块处理区域的数据按行进行位或就行了。此时要判断一行是否填满,这里也很简单,直接检查这一行的int型变量的值是否为0xffff,即-1。如果是,那就表示该行已经填满,否则还没有填满。

八、综上所述:我们可以看到,用位运算来处理俄罗斯方块中的一些操作,其关键的处理方法是非常直观的,只有图片显示方面不太好理解。这样一来,当程序编写出来后,我们就可以轻松地掌握到位移,位或,位与,位段等操作方式。星迷有空可以用上面讲述的方法尝试写一个俄罗斯方块游戏。祝你成功!

评分

参与人数 1小红花 +4 收起 理由
king + 4 支持LZ的研究精神

查看全部评分

发表于 2008-4-6 09:47:40 | 显示全部楼层
建议加精,非常不错!
发表于 2008-4-6 09:54:37 | 显示全部楼层
可惜在这里没权限
 楼主| 发表于 2008-4-6 09:58:58 | 显示全部楼层
其实,判断某个位上的值是否为1,其实有至少有两种方法:
方法一,将数值1左移至要判断的那个位上,然后进行位与,如果值为非零值,那么你要判断的位上的值就为了,否则为
方法二,将要判断的那个位向右移到bit0位上,然后除以取余,这个余数就是你要判断的那个位上的值.
发表于 2008-4-6 13:08:00 | 显示全部楼层
好东西,支持
发表于 2008-4-6 16:32:18 | 显示全部楼层
其实俄罗斯方块对速度要求不高
发表于 2008-4-20 16:19:57 | 显示全部楼层
对于巨型俄罗斯方块可能会体现出一些效率。。
发表于 2008-4-20 16:26:34 | 显示全部楼层
原帖由 jason911 于 2008-4-20 16:19 发表
对于巨型俄罗斯方块可能会体现出一些效率。。

估计宇宙级的可以吧。
发表于 2008-4-20 17:09:15 | 显示全部楼层
思想不错,支持下
发表于 2008-4-21 11:53:27 | 显示全部楼层
呵呵,还可以啊,支持一下~~~
发表于 2008-4-22 12:57:05 | 显示全部楼层
终于见到楼上了,拜一下。
发表于 2008-4-25 15:00:26 | 显示全部楼层
在TC环境下,借鉴薛老师的思想,写了个俄罗斯方块…结果大一菜鸟和准菜菜教员中引起轰动…
 楼主| 发表于 2008-5-1 01:07:20 | 显示全部楼层
可可,恭喜楼上的!
发表于 2008-6-14 05:15:03 | 显示全部楼层
顶先,再看
发表于 2008-7-11 14:29:24 | 显示全部楼层
总算明白了~谢谢!
您需要登录后才可以回帖 登录 | 加入易码

本版积分规则

Archiver|手机版|小黑屋|EMAX Studio

GMT+8, 2024-4-26 06:48 , Processed in 0.017906 second(s), 25 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表