在80后、90后的儿时记忆里,俄罗斯方块是必备的消遣小游戏,它的玩法非常简单基本大家都懂,但如何用编程语言开发一款儿时同款「俄罗斯方块」,恐怕知道的同学就很少啦。

位置掩码和旋转掩码

俄罗斯方块游戏中的格子一般是10列20行(10*20),我们称之为世界地图。

一般都是这种竖屏的界面

10*20的空间是用来盛放方块的,当方块落定之后位置便不能再改变。这个时候它会被保存到地图的状态中,我们给地图状态设计一个二维的数组。

方块有7种样式组成,最大的长宽是4个方格,为了在逻辑上比较好的处理所有类型的方块,我们构建了一个4x4的逻辑区域,用来统一描述所有类型的方块,包括显示、旋转等。这一区域就成为了它自身的空间整体,而方块被放到世界地图中时,也是以这样的整体加入进去的。

我们给方块定义了四种属性,分别是方向、颜色、种类以及在世界地图中的坐标。

方块可以做旋转,每经过四次旋转便会回到原始的状态,分别用0123来表示方块的四个方向,新产生的方块设定的是默认方向。

下图中的数值代表它在自己的空间内,哪些格子是有方块的,哪些是没有的。这是一个二进制的16位的显示掩码,0x4444代表的就是第一行第三列,第二行的第三列,第三行的第三列和第四行的第三列。

如果你没有做过数码管的显示,我用数字的角度来说明下:每个图是四行,分别用四个数字表示,数字使用十六进制;每行的四个方块从右到左表示1、2、4、8;那么你就明白了0x4444表示的图像了。

旋转掩码是用一个16bit的数据表示的,每个旋转掩码后面跟着的是一个16bit的显示掩码。

我们以S型方块作为参考来介绍,方向为零的时候它占据第一行的第二列第三列,第二行的第四列第三列,当它做一次旋转,方向由0到1这个过程中,它的旋转是会扫过这些位置,变成方向1的状态。在旋转过程中,如果它扫过的位置有其他方块占住,那么它便不能旋转。

还有,如果方块到达边缘的时候,旋转时超出了世界地图的范围,也是失败的,会继续维持现在这种状态。

旋转掩码和显示掩码组合在一起,旋转掩码的意义是,当前方向值下的方块,旋转到下一个方向值的时候,需要参考的障碍区域有哪些,以上就是位置掩码以及旋转掩码的介绍。

游戏中的主要逻辑

接下来我们来看下游戏中的主要逻辑判断。

移动逻辑

游戏中产生的方块,在产生之后,做周期性的下落运动。

同一时刻地图中只会有一个方块处于活动状态,可以在地图中做移动、旋转等操作,方块每次自由下落都会做一个下落判断,判断是否已经触底。

触底指的是,方块不能再往下移动,导致方块不能再往下移动的原因有2种,第一种是方块的下边缘已经在世界地图的边缘;第二种是方块再往下更新的位置,被其他已经落定的方块占据了。

如图上代码所示,方块移动的位置被其他方块所占据

方块触底之后,状态就由活动状态切换到了落定状态。此时方块的显示掩码中标注的所有可显示的块,都将会写入地图的状态中,以用来表明,这些块已经被占据了,写入地图状态中的值有两项属性:哪些块被占据了,已经被占据的块的颜色值。

假定方块当前的坐标是(x1,y2),从方块的当前移动方向中,我们可以得到方块等待判断是否可以移动过去的更新坐标(x2, y2)。

例如,方块向左移动,则:x2 = x1 - 1, y2 = y1;方块向右移动,则:x2 = x1 + 1, y2 =y1;方块向下移动,则:x2 = x1, y2 = y1 + 1;

那怎么判断方块是否可以移动成功呢?

根据方块的类型以及当前的方向值,从掩码表中可以拿到方块当前的显示掩码,方块是否能放置到新位置,只需要判断显示掩码中标明需要显示出来的位置,是否已经有其他方块占据,掩码中所有需要显示出来的位置,只要有一个位置被其他方块占据,本次移动判断失败,方块维持原有坐标

旋转逻辑

能够旋转涉及到一个方块是否改变它的方向,x、y是方块在世界地图中的坐标,block是它的状态值。

我们取它的种类、方向这两个属性,在4×4的空间里,计算出每一格对应到世界中的坐标。

“isBoxRotateMaskEmpty”这个代表什么意思呢?这是旋转掩码在旋转过程中要参照的点,方块旋转扫过的点,以及它落定之后的这几个点,这些点就是它的旋转掩码。

转写掩码值用一个七行四列的数组来保存,分别对应七种方块样式以及四个方向对应的值。它的高16位是旋转掩码,低16位是显示掩码。

方块的掩码表

方块是否能够旋转,先要看它的旋转掩码里面是为空,掩码为空则可以旋转,旋转完之后,需要判断方块新的坐标是否还在世界地图里,如果它超出边缘超出底线,那肯定是旋转不了的。

还有就是判断当前格子在世界地图中是否被其他的方块给占了,如果被占了的话,也是旋转不了的,这就是基本的旋转判定逻辑。

得分逻辑

方块落定之后,根据方块落定是的逻辑坐标,从上往下依次遍历地图中的4行状态值,当某一行的所有地图块的状态都是被占据状态,该行被判定为得分行,得分行会被消掉,当消完所有的得分行之后,得分行上方的所有未得分行,依次向下平移。

我们控制游戏难度的时候也是以这个为参考,玩家获得的分数越多,游戏难度越大。

我们可以通过修改方块出现的时间间隔,以及下落速度,来控制整个游戏的难度。

当玩家拿的分数越多,每消除一行的等级就会加一,分数是递增100,方块下降的速度是通过5的取模方式从1秒里面去扣,最小值是0.6秒。

如果某一行格子只要有一个空着的话,消除便失败。某一行的方块全部被消掉之后,上面的方块会向下平移,对应的行数需要刷新。

这便是关于得分的判断逻辑 。

游戏流程图

最后再来看下整个游戏玩的流程图。

游戏的核心逻辑是时间间隔,玩家点开始之后,每隔一段时间会调度一次,如果游戏没有结束,判断当前是属于暂停状态,没有说暂停的话,就做一个moveBlock。

当然,moveBlock有可能是玩家点了操纵的方向键,如果没点的话直接就返回了。紧接着处理方块的下落过程,判断它落定的时候是否结束了。

没有结束暂停的话,就处理移动,移动处理完之后,再去处理下落,如果刚好时间间隔已经到了,那它就会往下落一次,往下落的话有可能成功,也有可能失败。

判断结束后会出现游戏结束界面,可以选择是否重来一次,如果再来一次便会做一次重置。

这里需要做一个关于世界地图的补充说明,这里补充了一个地图的坐标系,游戏地图的坐标系X轴沿着水平方向向右,Y轴是沿着垂直方向向下增长,坐标系的原点是在左上角。

方块在逻辑空间中的坐标,是以左上角为参考点的,方块的坐标随着而改变。

出处:https://www.cnblogs.com/guchengnan/p/10657622.html

JS实现俄罗斯方块的更多相关文章

  1. 使用JS实现俄罗斯方块游戏

    简单的JS俄罗斯方块游戏源码 效果图: 代码如下,复制即可使用: <!DOCTYPE html> <html> <head> <meta charset=&q ...

  2. 纯JS实现俄罗斯方块,打造属于你的游戏帝国

    纯JS俄罗斯方块,打造属于你的游戏帝国. 本文原始作者博客 http://www.cnblogs.com/toutou 俄罗斯方块(Tetris, 俄文:Тетрис)是一款电视游戏机和掌上游戏机游戏 ...

  3. 用纯JS做俄罗斯方块 - 简要思路介绍(1)

    大家都知道俄罗斯方块是一款大众化的游戏了,我很小的时候就玩过,今年已经25岁了,可以说俄罗斯方块确实是历史悠久,做俄罗斯方块是我上个星期开始的想法.也许是由于自己从来没有写过这种东西吧,所以有生疏.代 ...

  4. 60行JS实现俄罗斯方块

    参考文献:http://www.cnblogs.com/jimaojin/p/5413857.html 原版: <!doctype html><html><head> ...

  5. [前端 3]纯Js制作俄罗斯方块游戏

    导读:在别人文章里看到了,然后写了一遍.结果出错了,然后调出来了,然后理解了一下,加了点注释,有一些想法.忘了在 哪一篇上面看的了,就贴不出来链接地址.原谅.呃,真没自己的东西,权当练打字了吧.其实, ...

  6. JS实现——俄罗斯方块

    把以下代码保存成Tetris.html文件,使用Google或360浏览器打开 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 4.0 Transit ...

  7. JAVASCRIPT实现网页版:俄罗斯方块

    HTML+CSS+JS实现俄罗斯方块完整版,素材只有图片,想要的下载图片按提示名字保存,css中用的时候注意路径!!主要在JS中!JS附有详细注释 效果: 按键提示:[键盘按键] 素材:图片名字与代码 ...

  8. 使用C#重写网上的60行 Javascript 俄罗斯方块源码 (带注释)

    在很久很久以前,就已经看过 60行Js的俄罗斯方块源码.无奈当时能力不够看明白,当时觉得就是个神作. 现在总算有空再看了,顺便用c#实现一遍(超过60行),顺道熟悉下Js API. 网上其他博客也有分 ...

  9. jQuery原型属性和方法总结

    从大四下学期开始了解jquery源码相关的东西,在回校参加毕业典礼(准确的说是参加补考挂科太多)期间便开始借着<jQuery>内幕学习jquery源码,然后在博客园写笔记也已经两个月了,也 ...

随机推荐

  1. windows server 2016 安装网卡驱动

    首先,联网分解为两个问题,一.WLAN(无线网).二.以太网(有线网) 一 .WLAN问题解决方案 1.打开服务器管理器 2.添加角色和功能 3.一直点下一步到“功能”,勾选 DirectPlay 和 ...

  2. ORM基础知识

    ORM基础知识 一.什么ORM? ORM是Object Relactional Mapping的缩写,即对象关系映射,是将关系型数据库中的数据库结构映射成对象,就可以通过面向对象思想编程. 二.常用的 ...

  3. hive 批量添加,删除分区

    一.批量添加分区:   use bigdata; alter table siebel_member add if not exists partition(dt='20180401') locati ...

  4. [工具]法国神器mimikatz 2.1.1 一键版 & PowerShell版

    无需任何参数,运行EXE即可自动读取Windows系统密码 EXE版需要其它功能请使用原版 (参数已写死仅读密码) 结果保存于当前目录mz.log EXE https://github.com/k8g ...

  5. python实现栈结构

    # -*- coding:utf-8 -*- # __author__ :kusy # __content__:文件说明 # __date__:2018/9/30 17:28 class MyStac ...

  6. Vue ----------- 了解, 展示json 数据

    Vue.js  是一套构建用户界面的渐进式框架. 优点: 与大型框架不同的是采用自底向上的增量开发的设计, 只聚焦于视图层,不仅易于上手,还便于与第三方库或既有项目整合 当与现代化工具链以及各种类库结 ...

  7. Sitecore 9 为什么数据驱动的组织选择它

    Sitecore 9使用个性化和机器学习来帮助客户提高数字营销对数字投资的回报 Sitecore 9比以往任何时候都更加智能.主要功能包括: 数据集中化 向后兼容性 简单的迁移 该平台简化了营销人员和 ...

  8. 利用TCHART做分离饼形图

    https://www.cnblogs.com/gaodu2003/archive/2009/06/18/1505720.html unit Unit1; interface ……type  TFor ...

  9. GoCN每日新闻(2019-09-23)

    1. 查看 Go 的代码优化过程http://xargin.com/go-compiler-opt 2. go 学习笔记之仅仅需要一个示例就能讲清楚什么闭包 https://segmentfault. ...

  10. 9. Scala隐式转换和隐式值

    9.1 隐式转换 9.1.1 提出问题 先看一个案例演示,引出隐式转换的实际需要=>指定某些数据类型的相互转化 object boke_demo01 { def main(args: Array ...