分享

HTML5 游戏开发实战 | 俄罗斯方块

 新用户62659642 2023-07-28 发布于湖南
图片

俄罗斯方块是一款风靡全球的电视游戏机和掌上游戏机游戏,它曾经造成的轰动与造成的经济价值可以说是游戏史上的一件大事。这款游戏看似简单但却变化无穷,游戏过程仅需要玩家将不断下落的各种形状的方块移动、翻转,如果某一行被方块充满了,那就将这一行消掉;而当窗口中无法再容纳下落的方块时,就宣告游戏结束。

可见俄罗斯方块的需求如下。

(1) 由移动的方块和不能动的固定方块组成。

(2) 一行排满消除。

(3) 能产生多种方块。

(4) 玩家可以看到游戏的积分。

本文开发俄罗斯方块游戏程序,俄罗斯方块游戏的运行界面如上图所示。

01

俄罗斯方块游戏设计的思路

俄罗斯方块形状设计

游戏中下落的方块有着各种不同的形状,要在游戏中绘画不同形状的方块,就需要使用合理的数据表示方式。常见的俄罗斯方块拥有7种基本的形状以及它们旋转以后的变形体,具体的形状如图12-2所示。

图片

■ 图12-2俄罗斯方块形状

每种形状都是由不同的黑色小方格组成的,如图12-3所示,在屏幕上只需要显示必要的黑色小方格就可以表现出各种形状,每一形状都是由4个小方格组成的,完全可以用4个点来表示。

图片

■ 图12-3俄罗斯方块示意图

4个点的坐标分别是什么呢?每个形状都有一个自己的坐标系。例如,S形可以如图12-4表示。

图片

■ 图12-4S形形状坐标系

S形的数据模型可以表示为4个点组成的数组:[ [0,-1],[0,0],[-1,0],[-1,1] ]。

如图12-5所示,T形的数据模型可以表示为4个点组成的数组:[ [-1,0],[0,0],[1,0] ,[0,1] ]。

图片

■ 图12-5T形形状坐标系

可以用同样的方法建立其他形状的数组模型,然后再将这7个形状的数组模型合起来组成一个大的数组。

另外,每个形状可以是单色,也可以有自己的颜色。增加颜色会增加编程的复杂度,但是也增加不了多少,所以该模型中也会考虑颜色。

最后,最好给每个形状一个编号,这样方便在形状数组和颜色数组中应用它们。

完成上面的分析后,就可以给出形状数据模型的代码了。

图片

俄罗斯方块游戏面板屏幕

游戏的面板是由一定的行数和列数的单元格组成的,游戏窗口面板屏幕如图12-6所示。

图片

■ 图12-6屏幕网格

屏幕由20行10列的网格组成,为了存储游戏画面中的已固定方块采用二维数组lines,当相应的数组元素值非零(数组元素值为0,表示此单元格无方块),则绘制一个对应彩色小方块。在窗口面板中显示一个俄罗斯方块形状,只需要把面板中相应的单元格绘制为彩色方块即可,如图12-7所示的面板中显示一个L形方块,只需要按照L形方块形状数组定义,将它的数据用Paint()函数绘制到窗口面板即可。

而方块下落的基本处理方式就是当前方块下移一行,然后根据当前方块的数组的数据和存储的固定方块的面板二维数组lines,重新绘制一次屏幕即可,如图12-7所示。所以要使用一个坐标(row,col)记录当前方块形状所在的行号row和列号col。

图片

■ 图12-7L形方块下落前和下落后

定位和旋转形状

1. 定位

上面说到每个形状都是在自己的坐标系里面描述的,另外还有一个屏幕上的全局坐标系,用来给形状定位,这样就需要一个方法将形状的4个点从自身坐标系转换到屏幕上的全局坐标系,从而给形状定位。

假如S形在自身坐标系中4个点的坐标为:[[0,-1],[0,0],[-1,0],[-1,1]]。它当前在屏幕上全局坐标系位置为:[12,8],则4个点转换为全局坐标系的坐标为:[[0+12,-1+8],[0+12,0+8],[-1+12,0+8],[-1+12,1+8]]。这样,就完成了S形的全局坐标转换。

这里需要注意一个问题,形状自身坐标系是用(x,y)描述的,而全局坐标系为了逻辑上更直观,是用(row,col)描述的,所以在实际编程中并不是像上面那样转换的,而是:[[-1+12,0+8],[0+12,0+8],[0+12,-1+8],[1+12,-1+8]]即先将x变为col,y变为row,再转换为全局坐标系。

2. 旋转

旋转是在形状的自身坐标系中围绕形状的原点完成的,其公式很简单,每个点旋转后的坐标与旋转前的坐标的关系如下(向右旋转)。

x'=y

y'=-x 

注意,正方形形状不发生旋转。

根据上面的分析,可以使用两个全局方法,用来对形状进行全局定位和旋转。

translate(data.row.col)函数将形状自身的坐标系转换为屏幕的全局坐标系,(row,col)为当前形状原点在屏幕中的位置。

图片

每种形状向右旋转就会形成一个新的形状,rotate(data)函数可以得到当前形状的方块旋转后的坐标数组。

图片

图片

3. 游戏流程

俄罗斯方块游戏就是用一个定时器控制方块下落并重绘的过程,用户可以利用键盘输入改变方块状态。每隔一定的时间就重画当前下落方块和lines存储的固定方块,从而看到动态游戏效果。

俄罗斯方块下落过程中可能遇到种种情况。例如,是否需要消行,是否需要终止下落并且产生新的形状的方块等。具体的判断流程如下:首先判断是否可以继续下落,可以下落则row++即可;如果方块不能够继续下落,则将当前形状的方块添加到面板二维数组lines中,界面产生新的形状的方块。然后,判断是否需要消行。最后,请求重新绘制屏幕。

02

俄罗斯方块游戏设计的步骤

游戏页面index.html

图片

设计脚本

1. 设计方块类Block

方块类Block中定义方块的类型ID,存储方块的形状二维数组data以及颜色。设计了将形状自身的坐标系转换为屏幕的坐标系的translate(row,col)函数,参数(row,col)为当前形状方块的原点在屏幕Map中的位置。rotate()函数可以获取当前形状方块旋转后的坐标数组。

图片

图片

另外,程序中将各方块形状编号:Z形编号1,S形编号2,竖条形编号3,T形编号4,正方形编号5,L形编号6,反L形编号7。所有方块的形状采用数组Shapes存储。通过编号从数组Shapes中获取方块的形状信息。

图片

图片

2. 设计游戏容器Map类

游戏容器Map类是游戏实例,应先定义游戏面板大小,在游戏面板中存储所有方块的“容器”——二维数组lines,初始时每个元素存储为NoShape(0),表示此格子处无方块。

图片

isFullLine (row)函数判断一行是否全部被占用(满行),如果有一个格子为 NoShape 则返回 False。

图片

预先移动或者旋转形状,调用isCollide(data)函数分析形状中的4个点是否有以下碰撞情况。

(1) col<0 || col>this.width,说明超出左右边界。

(2) row==this.height,说明形状已经到最底部。

(3) 任意一点的shape_id不为NoShape,则发生碰撞。

如果发生碰撞,则放弃移动或者旋转。

图片

形状在向下移动的过程中发生碰撞,appendShape=function (shape_id,data)则将形状加入lines容器中固定下来。

图片

3. 设计游戏逻辑类GameModel

游戏逻辑类GameModel实现游戏控制,首先定义游戏面板map、当前的俄罗斯方块currentBlock、下一个的俄罗斯方块nextBlock以及当前的俄罗斯方块所在位置等。

图片

图片

其次调用CreateNewBlock()函数产生新的俄罗斯方块。它先复制下一个形状this.nextBlock,再产生下一个俄罗斯方块。

图片

以下是控制形状方块左右移动、旋转和下移,并且保证左右移动时和lines中存储的固定方块、边界不碰撞。如果碰撞则恢复数据放弃移动。

图片

同样保证旋转时和lines中存储的固定方块、边界不碰撞。如果碰撞则恢复数据放弃旋转。

图片

图片

方块下落需判断是否“触底”或接触到其他已落方块。如果“触底”则固定到游戏面板上,此时要处理满行和游戏结束的判断,同时产生新的俄罗斯方块。

图片

4. 游戏主程序

在定时事件中,完成下落功能。

图片

图片

以下是消息事件处理。

图片

图片

以下才是真正的绘制代码,调用clearline(row)函数绘制清除行的暂停效果。

图片

调用paint()函数绘制游戏屏幕。它将lines存储的所有固定方块画到游戏面板中,同时当前方块画到游戏面板中和下一个方块画到游戏面板右侧提示预览区中。

图片

图片

至此,俄罗斯方块游戏编写完成。

04

参考书籍



图片

HTML5网页游戏设计从基础到开发(第2版·微课视频版)

作者:夏敏捷、尚展垒
定价:69.90元
ISBN:9787302629771

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多