搜索
首页web前端H5教程动手打造html5俄罗斯方块的(图文)

在正文开始之前还要啰嗦一下,标题中所谓自给自足,是在没有参考任何设计思路的前提下去开发这游戏的,你可能会不解,如果参考优秀的思路,岂不是事半功倍,当然,参考与不参考都有利,我只说不参考的利,当我煞费苦心、历经数十个BUG修改,终于完成一件作品的时候,我可以很自豪地对别人说:“看,我开发的游戏!”当然,创意不是我的,但这并不影响自己那份“虚荣心”,为一款经典的游戏赋予自我的理解,并将它融入游戏中,岂不是一件有意思的事,而且,回过头来再看一看别人的思路,有时会拍案而起,“这个我当初怎么就没想到呢?”,“原来这个问题可以这样解决”,“这个设计思路比我的思路好多了!”,诸如此类总比开始就直接看别人的思路而阻塞自己的思考要强得多,对吧?

好叻,正文开始~

想先看效果的,先跳转试玩一下吧!

俄罗斯方块,主游戏界面应该由一个一个的方块组成,如下图,当然成品里面这些网格是看不到的,这里只是助于理解,主界面尺寸为400×500,设定每块砖(网格)的尺寸为20×20,则每行有20个砖块,每列有25个砖块。相关代码:

brickWidth = 20,    //砖块大小
width = 400, height = 500;  //画布宽高,20X25

提到主界面的网格,就要提到一个非常重要的变量了,它就是BOARD,一个二维数组,形象化地说其尺寸是20×26,存储的值为0或1,0表示该位置没有砖块,1表示该位置有砖块,在接下来的一些判定中有重要作用,游戏细心的同学可能发现,为什么是20×26,而不是对应主界面网格的20×25,我在一开始的时候也是设定为20×25的,后来注意到如果加一行而且这一行的值都为1就可以很容易判断砖块是否到触及主界面底部了。相关代码:

// 初始化BOARD,注意纵向有26个,最后一排用来判断是否触底
for(i=0;i<20;i++){
    BOARD[i] = [];
    for(j=0;j<26;j++) {
        if(j==25) {
            BOARD[i][j] = 1
        } else {
            BOARD[i][j] = 0;
        }
    }
}


接下来看由4个砖块组成的“形状”,有五种,为了好描述,我把它们为别命名,Tian(田),Chu(锄头),Tu(凸起来),Thunder(闪电),Line(一横),哈哈有趣的名字,原谅我没找到它们的英文名字吧。

首先定义一个砖头类Brick:

function Brick() { }

其下有几个原型变量和方法:

Brick.prototype.embattle = null;    //砖块的布局(需重载)
Brick.prototype.isOverturn = 0; //是否翻转
Brick.prototype.originX = 9;    //砖头的绘制起点X
Brick.prototype.originY = -3;    //砖头的绘制起点Y
Brick.prototype.direction = 0;  //砖头朝向
Brick.prototype.autoMoveTimer = null;   //自动移动计时器
Brick.prototype.draw = function() { …… }    //画砖块的方法
Brick.prototype.move = function(moveX, moveY) { …… }    //移动的方法
Brick.prototype.autoMove = function() { …… }    //自动移动的方法
Brick.prototype.change = function() { …… }    //变换砖头朝向

Brick的子类有:Tian,Chu,Tu,Thunder,Line五个,每个子类中都重载Brick的embattle变量,embattle是什么,英译中的意思是布阵,这个阵是个什么阵呢?首先,同学们要理解我的思路,用Tu的embattle来举例,其代码如下:

this.embattle = [
    [ [0,4,5,8], [1,4,5,6], [1,4,5,9], [0,1,2,5] ],  //布局表为4X4表格,数字为砖头位置
    [ [0,4,5,8], [1,4,5,6], [1,4,5,9], [0,1,2,5] ]   //次行为翻转的情况];

embattle是一个三维数组,第一维是是否翻转isOverturn(形象来说就像图片的水平翻转),第二维是方向direction(上左下右),第三维是形状的4个砖块分布情况,我把每个新形状对象定义在一个4×4的阵中,例如,Tu的this.embattle[0][0]为[0,4,5,8],数字即该砖块的所在位置,如下图:

所以要确定一个形状的位置和样子,需要isOverturn确定是否翻转,需要direction确定其方向,需要originX和originY确定“阵”的位置。

接下来,分别解释Brick的4个原型方法。

Brick.prototype.draw

ctx.fillStyle = &#39;rgb(&#39;+Math.floor(Math.random()*256)+&#39;,&#39;+Math.floor(Math.random()*256)+&#39;,
&#39;+Math.floor(Math.random()*256)+&#39;)&#39;;
for(i=0;i<4;i++) {
    tmp = this.embattle[this.isOverturn][this.direction][i];
    ctx.fillRect((this.originX+tmp%4)*brickWidth, (this.originY+Math.floor(tmp/4))*brickWidth, brickWidth, brickWidth);
    ctx.strokeRect((this.originX+tmp%4)*brickWidth+1, (this.originY+Math.floor(tmp/4))*brickWidth+1, brickWidth-2, brickWidth-2);   //注意+1和减2
}

有上面说的确定形状的位置和样子的方法,之后就是纯粹canvas画图,4个砖块一个一个地画,不要看代码很长其实就是那么一点点,originX、originY和砖块在阵中的位置就可以确定画砖块的起点了。注意到代码的注释了没有,画边框的时候,它是从起点向外面画的,就像我把一个塑料袋套在另一个塑料袋的外面,为了以后的清除的方便且不影响其他的砖块,把边框画进fillRect的领土,就像我现在把这个塑料袋不套在外面而是放进这另一个塑料袋里面一样,就这个意思。

Brick.prototype.move

这是最长的一个了,移动的时候,moveX和moveY表示横纵的增量,没有同时非0的情况(这是人为的设定,要么横向移动要么纵向移动),当然要判断即将移动到的位置是否违规

横向:

如果阵贴靠主界面左侧则不能向左移即moveX不能为-1

(this.originX==0 && moveX==-1)

判断右边时比较麻烦,因为不能直接用阵来判断是否贴靠右侧(看前面的图就知道阵的右边和下边可能没有砖块的),这时要一个个地判断4个砖块是否有至少有一个在最右,这时不能向右移动

|| (this.originX+tmp[0]%4==19 && moveX==1)
|| (this.originX+tmp[1]%4==19 && moveX==1)
|| (this.originX+tmp[2]%4==19 && moveX==1)
|| (this.originX+tmp[3]%4==19 && moveX==1)

最后还要判断即将到达的位置是否已经有砖块了。

|| (BOARD[this.originX+tmp[0]%4+moveX][this.originY+Math.floor(tmp[0]/4)]==1)
|| (BOARD[this.originX+tmp[1]%4+moveX][this.originY+Math.floor(tmp[1]/4)]==1)
|| (BOARD[this.originX+tmp[2]%4+moveX][this.originY+Math.floor(tmp[2]/4)]==1)
|| (BOARD[this.originX+tmp[3]%4+moveX][this.originY+Math.floor(tmp[3]/4)]==1)

纵向:

即将到达的位置是否已经有砖块了,注意到下面的代码的&& moveX==0,原来是没有的,后来发现每次砖块怎么刚刚靠上下面堆着的砖块就不能再移动了,原来横向移动的时候也进行了这个判断,即刚刚靠上下面的砖块,如果这时想左右移动,但下方有砖块,但是问题来了,下面有没有砖块跟我左右移动有什么关系呢?是吧。

if((as==1 || bs==1 || cs==1 || ds==1) && moveX==0) { …… }

纵向终止判断里面主要做了几件事:清除autoMoveTimer,设置BOARD在该形状当前位置的值为1,有可以消除的整行就消除,加分改分,判断胜利/失败,删除当前对象,召唤下一个形状。

横纵都没违规时:

这时,把该形状前一个位置的砖块清除,更新originX和originY,再画出来。

for(i=0;i<4;i++) {
    tmp = this.embattle[this.isOverturn][this.direction][i];
    ctx.clearRect((this.originX+tmp%4)*brickWidth, (this.originY+Math.floor(tmp/4))*brickWidth, brickWidth, brickWidth);
}
this.originX += moveX;
this.originY += moveY;
this.draw();

Brick.prototype.autoMove

只做一件事,设置计时器,定时向下移动。

var status, self = this;this.autoMoveTimer = setInterval(function() {
    status = self.move(0,1);
},speed);

Brick.prototype.change

改变形状的朝向,很好办啊,不是有embattle数组了吗?当然没有那么简单,不只是换个数组这么简单。要考虑改变方向之后占用的位置是否已经有砖块了,如果形状是贴着主界面右边界就更糟糕了,比如原来是竖着的Line,改变其方向变为横,占用阵的0、1、2、3,如果Line贴着右边界,originX为19,变为横向,占用阵的0、1、2、3,后面三个砖块已经溢出了主界面。

解决方案是:如果有越界的砖块就把阵往左挪一挪,直到不再越界。

while(ox+tmp[0]%4 > 19 || ox+tmp[1]%4 > 19 || ox+tmp[2]%4 > 19 || ox+tmp[3]%4 > 19) {
    ox -= 1;
}

最后,如果都没事,就可以清除原位置,画出改变方向之后的形状了。

并不是太完美,因为有些卡位的情况没考虑进来,什么是卡位,看下图,你知道Line实例调用change方法的结果是什么了吗?事实上,它不应该成功改变方向的,对吧?还有其他一些卡位的情况。

Brick的4个原型方法就介绍到这里了。现在如果我要在右边的信息界面显示下一个的形状,最直接的方法就是,通过该形状的构造函数实例化一个对象,为防止其自动调用autoMove,为构造函数添加了isModel来判断是不是供提示用的。

还有按键事件监听、NextBrick函数和deleteObj自己看看吧,很容易看懂,游戏的入口就是NextBrick函数。

还有就是,我无法确定deleteObj是否真的成功让GC把对象回收了。

还有就是,我本想增加关卡功能,因为可以自由设置速度(speed变量),就把这功能放一放了。

以上是动手打造html5俄罗斯方块的(图文)的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
H5:如何增强网络上的用户体验H5:如何增强网络上的用户体验Apr 19, 2025 am 12:08 AM

H5通过多媒体支持、离线存储和性能优化提升网页用户体验。1)多媒体支持:H5的和元素简化开发,提升用户体验。2)离线存储:WebStorage和IndexedDB允许离线使用,提升体验。3)性能优化:WebWorkers和元素优化性能,减少带宽消耗。

解构H5代码:标签,元素和属性解构H5代码:标签,元素和属性Apr 18, 2025 am 12:06 AM

HTML5代码由标签、元素和属性组成:1.标签定义内容类型,用尖括号包围,如。2.元素由开始标签、内容和结束标签组成,如内容。3.属性在开始标签中定义键值对,增强功能,如。这些是构建网页结构的基本单位。

了解H5代码:HTML5的基本原理了解H5代码:HTML5的基本原理Apr 17, 2025 am 12:08 AM

HTML5是构建现代网页的关键技术,提供了许多新元素和功能。1.HTML5引入了语义化元素如、、等,增强了网页结构和SEO。2.支持多媒体元素和,无需插件即可嵌入媒体。3.表单增强了新输入类型和验证属性,简化了验证过程。4.提供了离线和本地存储功能,提升了网页性能和用户体验。

H5代码:Web开发人员的最佳实践H5代码:Web开发人员的最佳实践Apr 16, 2025 am 12:14 AM

H5代码的最佳实践包括:1.使用正确的DOCTYPE声明和字符编码;2.采用语义化标签;3.减少HTTP请求;4.使用异步加载;5.优化图像。这些实践能提升网页的效率、可维护性和用户体验。

H5:网络标准和技术的发展H5:网络标准和技术的发展Apr 15, 2025 am 12:12 AM

Web标准和技术从HTML4、CSS2和简单的JavaScript演变至今,经历了显着的发展。 1)HTML5引入了Canvas、WebStorage等API,增强了Web应用的复杂性和互动性。 2)CSS3增加了动画和过渡功能,使页面效果更加丰富。 3)JavaScript通过Node.js和ES6的现代化语法,如箭头函数和类,提升了开发效率和代码可读性,这些变化推动了Web应用的性能优化和最佳实践的发展。

H5是HTML5的速记吗?探索细节H5是HTML5的速记吗?探索细节Apr 14, 2025 am 12:05 AM

H5不仅仅是HTML5的简称,它代表了一个更广泛的现代网页开发技术生态:1.H5包括HTML5、CSS3、JavaScript及相关API和技术;2.它提供更丰富、互动、流畅的用户体验,能在多设备上无缝运行;3.使用H5技术栈可以创建响应式网页和复杂交互功能。

H5和HTML5:网络开发中常用的术语H5和HTML5:网络开发中常用的术语Apr 13, 2025 am 12:01 AM

H5与HTML5指的是同一个东西,即HTML5。HTML5是HTML的第五个版本,带来了语义化标签、多媒体支持、画布与图形、离线存储与本地存储等新功能,提升了网页的表现力和交互性。

H5指的是什么?探索上下文H5指的是什么?探索上下文Apr 12, 2025 am 12:03 AM

H5referstoHTML5,apivotaltechnologyinwebdevelopment.1)HTML5introducesnewelementsandAPIsforrich,dynamicwebapplications.2)Itsupportsmultimediawithoutplugins,enhancinguserexperienceacrossdevices.3)SemanticelementsimprovecontentstructureandSEO.4)H5'srespo

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具