俄罗斯方块
使用画布,设计俄罗斯方块。
ENGLISH VERSION HERE
组件设计界面:
组件设计界面很简单(很简陋):
6个按钮:开始游戏、左移、右移、逆时针转、顺时针转、下落
1个画布:宽度设为240,高度设为480
1个计时器,1个对话框
设计思路:
我们将画布分为20行、10列的格子,俄罗斯方块就是在这200个格子内移动、旋转。
给每个格子编号(从0开始),如图:
图中的白色部分就是我们的画布,外面包围的灰色一圈,就代表画布的边框,俄罗斯方块不能移动到这些边框上。
所有的棋盘游戏,都是背后的数据支撑。
我们初始化一个棋盘数据变量,记录每个小格子上的颜色。
棋盘数据初始化时是这样的:
9,9,9,9,9,9,9,9,9,9,9,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,0,0,0,0,0,0,0,0,0,0,9,
9,9,9,9,9,9,9,9,9,9,9,9
这些数字应该是在一行上的,这里分为22行12列,是为了便于观察。
在画布的边框格子,我们都填上9。中间画布的位置都填上0。
以后如果这个位置被某个组合占据,就把这个位置标记为组合的编号。
给出每个方块的位置,我们可以求出他所在的行或者列。注意,这个行和列是从0开始的。
比如0号位置,就是0行0列。13号位置就是1行1列。250号位置就是20行10列。
相对于可见的画布来说,正好符合我们的习惯。
初始化一个颜色列表变量,分别代表7种不同的组合的颜色,
画出小方块:
每个俄罗斯方块的不同组合都是由4个小方块拼成。若需要画出组合,先需要画出小的方块。
每个小方块都有不同的编号,只要给定一个编号,我们就可以在这个位置画出小方块。
我们在设计界面把画布设为240宽480高,这样每个格子就是24宽24高。
首先根据方块的位置编号,求出他所在的行和列。把线段的长度和宽度都设为22,这样每两个格子之间有个空隙。
好了,现在我们就可以连接手机伴侣,测试下我们的画方块过程了。
是不是正好画在画布的左上角?把13改成250,是不是正好画在右下角?
如果不是,说明你的画方块过程有错误,请仔细改正。
现在我们已经可以在任意位置画出小方块了,如何才能画出一个组合(4个方块)呢?
我们只要知道组合所占据的4个方块的编号就可以了。
俄罗斯方块共有7种不同的类型:分别是L型,J型,Z型,S型,T型,田字型,一字型。我们把他们称为7种组合。
每个组合可以旋转,每旋转90度是一个造型,共有4个造型(有的造型有重复)。这样,旋转组合就是切换不同的造型了
每个造型我们给他指定一个基点。这样,移动组合就是移动他的基点。
下面进入重点:造型的偏移表
举例来说,对于L型。
如果我们把它放在19,31,43,44号位置上。
我们指定31是他的基点(也可以指定其他位置作为基点),这样四个位置减去基点31的差就是:-12,0,12,13。
我们把这个称为该造型的偏移表。
我们把它逆时针旋转90度,变为:
这时,他占据的四个位置相对于31的位移变成了:-1,0,1,-11
我们把它再次逆时针旋转90度,变为
这时,他占据的四个位置相对于31的位移变成了:-13,-12,0,12 (四个格子的顺序是可以打乱的)。
再次旋转90度
位移变成了-1,0,1,11
注意,这个偏移表只跟这个组合的种类和造型(旋转)有关,跟她的位置(基点)无关。
比如第一种造型我们把他向左平移2格到:
这时,基点移动到29,他的四个格子的偏移表还是:-12,0,12,13。
使用这个方法,我们记下7种组合每个造型的偏移表:
同一种组合的不同偏移表之间用\n 连接。
注意这里用的是"csv转列表"块,而不是"csv行转列表"块。
对于田字形和一字型,可能部分造型有重复。为了跟其他组合都是4种造型相匹配,我们就把他写4次。
现在就可以画出某种组合的某种造型了:
确定了组合编号和组合造型,我们就确定了组合的偏移表。
偏移表中的每个偏移数值分别加上组合中心,就知道了组合所占据的位置编号了,这样就可以画出这个组合。
生成新组合,我们都把它显示在画布上部中间位置(17号)。
即组合中心设为17,随机生成编号和造型
每次点开始,都在画布上方画出不同种类不同造型的组合了。
这样,左移、右移、顺转、逆转就简单了:
左移就是把组合中心向左移动一个,就是组合中心数值减1,
右移就是把组合中心向右移动一个,就是组合中心数值加1,
下移就是把组合中心向下移动一个,就是组合中心数值加12。
(记得先点开始,随机产生一个组合)
逆时针转就是把造型加1,顺时针转就是把造型减1。
注意,组合造型只能在1-4之间切换。每次造型改变后必须更新偏移表。
有没有发现组合可能会移动或者旋转出了画布?如何避免呢?
比如图中L型组合要往左移动,但是要前往的格子内保存的是9(非0值),这样就不能移动。
要前往的位置占据的格子只要有1个的值为非0,就不能移动(或者旋转)。
之所以位置+1,是因为格子位置编号是从0开始,而列表取值索引是从1开始。
为了要检测移动和旋转两种操作,需要传入两个参数。记住如果造型变了,就要更新新位置偏移表。
每次移动或者旋转前,先检测要去往或者旋转后占用的地方是不是可以到达的(都为空格)。只有可以到达才移动或者旋转。
修改移动和旋转事件:
怎么让组合自动下落呢?就必须请出计时器了。
每次游戏开始,都让计时器开始计时。
每次计时,判断可否向下移动(组合中心+12就是下移)。如果碰到底边或者其他组合,就重新在画布上部生成新组合。
如果你测试这个代码,就会发现触底的组合并没有留在那里,而是消失了。
因为我们没有把触底的组合保存到“棋盘数据”变量:
添加后还要显示出来:
循环取出棋盘数据中的每个数(颜色,也是这格方块曾经被某个组合占据)。
如果这个数不是9(边框),也不是0(空白格),就在这个位置画方块。
修改计时器事件:
生成新组合之前,保存数据到棋盘数据。
修改”重绘画布”过程:
现在我们的组合可以左右移动、顺转逆转、定时下落了。
那什么时候游戏结束呢?就在新生成的组合无法安放时:
有没有发现在生成新组合时经常莫名其妙就提示游戏结束了?
这是因为我们把初始的组合中心设为17,非常靠近上边缘,而有的组合造型就出了边界了。
为了解决这个问题,我们把棋盘数据的第一行,也就是上边缘数据由9,9,9,9,9,9,9,9,9,9,9,9共12个9,
改为9,0,0,0,0,0,0,0,0,0,0,9 也就是上边缘开放。因为我们没有上移的操作,不会影响程序其他部分运行。
下面是本游戏的另一个重点:
如何消除一行方块?
当棋盘数据某一行的所有位置都是非0值,这一行的方块就可以移除。
比如图示的倒数第二行,也就是画布的倒数第一行,分别是9,1,1,6,6,4,4,7,7,7,7,9,
这12个数没有0值,说明这一行可以消除,我们就把这一行从“棋盘数据”变量中删除。
重复检查第20行,第19行...到第1行,并统计一共删除的行数。最后在画布第一行插入12个数:
9,0,0,0,0,0,0,0,0,0,0,9,删除了几行,插入几行。
根据消除的行数计算得分:1行10分,2行30分,3行60分,4行100分。不可能同时消除5行及以上的。
修改计时器计时事件,在生成新方块之前检测消除方块并计算得分:
修改开始游戏事件,游戏开始时重新计分:
最后一个,快速下落事件:
重复检查可否下移一格(组合中心+12),若可以,再次下移一格,直到无法下移为止。
我们在回头看下“消除方块”这个过程:
实际上每次消除时不可能有20行都能消除,可以消除的行只可能在当前组合占据的行中产生。
我们只要找到当前组合占据的行,依次判断这几行可否消除就可以了。
为什么在13位置插入呢?因为13位置就是棋盘数据第二行的第一个数字。