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

效果:

按键提示:[键盘按键]

素材:图片名字与代码里对应

  1、背景图片:tetris.png

  

  2、失败时候的弹出框图片:game-over.png

  

  3、七种色彩小方块图片:

    I.png:

    J.png:

    L.png:

    O.png:

    S.png:

    T.png:

    Z.png:

HTML代码

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>俄罗斯方块 — 经典完整版</title>
<link rel="stylesheet" href="css/tetris.css"/>
<script src="js/shapes.js"></script>
<script src="js/tetris.js"></script>
</head>
<body>
<div class="playground">
<p>SCORE:<span>0</span></p>
<p>LINES:<span>0</span></p>
<p>LEVEL:<span>1</span></p>
</div>
</body>
</html>

CSS代码

.playground  {
width: 525px;
height: 550px;
margin: 20px auto 0 auto;
position: relative;
background-image:url("tetris.png");
}
.playground img { position: absolute;}
.playground p {font-size: 30px;
font-family: 'SimHei';
font-weight: bold;
color: #667799;
position: absolute;
left:305px;
top:120px;
}
.playground p+p { top:176px; }
.playground p+p+p { top:232px; }

JAVASCRIPT代码:分两段附有详细步骤解释

  1、tetris.js

window.$=HTMLElement.prototype.$=function(selector){
return (this==window?document:this).querySelectorAll(selector);
}
var tetris={
RN:20,//总行数
CN:10,//总列数
CSIZE:26,//每个格子的宽高都是26px
OFFSET_X:15,//每个单元格的左侧都要加15px
OFFSET_y:15,//每个单元格的上面都要加15px
pg:null,//保存游戏主界面对象
currShape:null,//专门保存正在移动的图形对象
nextShape:null,//八、专门保存下一个图形
interval:500,//每秒重绘一次==>下落的速度
timer:null,
wall:[],//六、保存所有停止的下落的方块
state:1,//十、保存游戏当前状态
STATE_RUNNING:1,//十、游戏正在运行
STATE_GAMEOVER:0,//十、游戏结束
STATE_PAUSE:2,//十、游戏暂停
IMG_GAMEOVER:"img/game-over.png",
IMG_PAUSE:"img/pause.png",
SCORES:[0,10,50,80,200],//十三,要加的分数档位
score:0,//十三、当前总分
lines:0,//十三、当前总行数
//十、为游戏添加不同状态的图片
paintState:function(){//根据当前游戏状态,为游戏添加不同的图片
var img=new Image();
switch(this.state){
//如果当前状态是STATE_GAMEOVER
case this.STATE_GAMEOVER:
// img.src设置为IMG_GAMEOVER
img.src=this.IMG_GAMEOVER;
break;
//如果当前状态是STATE_PAUSE
case this.STATE_PAUSE:
// img.src设置为IMG_PAUSE
img.src=this.IMG_PAUSE;
}
//将img追加到pg中
this.pg.appendChild(img);
},
init:function(){
this.pg=$(".playground")[0];
//创建一个随机图形的对象存在currShape中
this.currShape=this.randomShape();
this.nextShape=this.randomShape();
//六、将wall数组初始化为RN的空数组对象
for(var i=0;i<this.RN;i++){
this.wall[i]=[];
}
this.score=0;//十六、初始化
this.lines=0;//十六、初始化
this.state=1;//十六、初始化
this.paint();
//三、
this.timer=setInterval(function(){
//调用tetris的drop方法
tetris.drop();
//再调用tetris的paint方法;
tetris.paint();
},this.interval);
//十一、
document.onkeydown=function(){
var e=window.event||arguments[0];
switch(e.keyCode){
case 37: tetris.moveL();break;//左
case 39: tetris.moveR();break;//右
case 40: tetris.drop();break;//下
//十五步、
case 38: tetris.rotateR();break;//上键控制右边旋转
case 90: tetris.rotateL();break;//字母Z键控制控制左边旋转
//十六步
case 80: tetris.pause();break;//字母P键:暂停
case 81: tetris.gameOver();break;//字母Q:结束游戏
case 67: tetris.myContinue();break;//字母C,在暂停后有效:暂停后,继续游戏
case 83: //游戏结束后,重新开始
if(this.state==this.STATE_GAMEOVER){
tetris.init();
}//字母S键:重新开始游戏
}
}
},//init的结束
//十六、暂停,开始,继续、结束
gameOver:function(){
this.state=this.STATE_GAMEOVER;
clearInterval(this.timer);
this.timer=null;
this.paint();
},
pause:function(){
if(this.state==this.STATE_RUNNING){
this.state=this.STATE_PAUSE;
}
},
myContinue:function(){
if(this.state==this.STATE_PAUSE){
this.state=this.STATE_RUNNING;
}
},
//十五、变形
rotateR:function(){//按键上,向右旋转
if(this.state==this.STATE_RUNNING){//十六
this.currShape.rotateR();
if(this.outOfBounds()||this.hit()){//验证不通过
this.currShape.rotateL();
}
}
},
rotateL:function(){//按键Z,向左旋转
if(this.state==this.STATE_RUNNING){
this.currShape.rotateL();
if(this.outOfBounds()||this.hit()){//验证不通过
this.currShape.rotateR();
}
}
},
//十一、
moveR:function(){
this.currShape.moveR();
if(this.outOfBounds()||this.hit()){//验证不通过
this.currShape.moveL();
}
},
moveL:function(){
this.currShape.moveL();
if(this.outOfBounds()||this.hit()){//验证不通过
this.currShape.moveR();
}
},
outOfBounds:function(){//检查当前图形是否越界
//当前shape中任意一个单元格的col<0或>=CN
var cells=this.currShape.cells;
for(var i=0;i<cells.length;i++){
if(cells[i].col<0||cells[i].col>=this.CN){
return true;
}
}
return false;
},
hit:function(){//检查当前图形是否碰撞
//当前shape中任意一个单元格在wall中相同位置有格
var cells=this.currShape.cells;
for(var i=0;i<cells.length;i++){
if(this.wall[cells[i].row][cells[i].col]){
return true;
}
}
return false;
},
//四、重绘所有的格子,分数等的方法
paint:function(){
//把所有的img格子删除,再重绘
/*结尾的4个/<img(.*?){4}>*/
this.pg.innerHTML=this.pg.innerHTML.replace(/<img(.*?)>/g,"");
this.paintShape();
this.paintWall();
this.paintNext();
//十三
this.paintScore();
this.paintState();//十、
},
//十三、计分
paintScore:function(){//找到span元素
//第一个span中放this.score
$("span")[0].innerHTML=this.score;
//第二个放this.lines
$("span")[1].innerHTML=this.lines;
},
drop:function(){
//判断能否下落
if(this.state==this.STATE_RUNNING){//该行是第十六步加的
if(this.canDrop()){
this.currShape.drop();
}else{//六、否则
//六、如果不能下落,就将图形中每个cell,放入wall数组中
this.landIntoWall();
//十二、消行、并计分
var ln=this.deleteLines();//消除并返回本次删除的行数
//十三、计分
this.score+=this.SCORES[ln];
this.lines+=ln;
//九、如果游戏没有结束才。。
if(!this.isGameOver()){
//七、将等待的nextShape,换到currShape
this.currShape=this.nextShape;
//七、
this.nextShape=this.randomShape();
}else{//十、否则,一级结束
clearInterval(this.timer);
this.timer=null;
this.state=this.STATE_GAMEOVER;
this.paint();//手动绘制一次
}
}
}
},
//十二、消行,并计分
deleteLines:function(){//检查wall中每一行是否要消除
//遍历wall中每一行,定义lines变量存本次共删除的行数line
for(var row=0,lines=0;row<this.RN;row++){
//如果当前行是满的:isFull(row)
if(this.isFull(row)){
// 就删除当前行:
this.deleteL(row);
// 每删除一行,lines++
lines++;
}
}
return lines;
},
isFull:function(row){//判断指定行是否已满
//取出wall中第row行,存在line变量中
var line=this.wall[row];
//遍历line中每个cell
for(var c=0;c<this.CN;c++){
// 只要当前cell无效
if(!line[c]){
return false;
}
}//遍历结束后
return true;
},
deleteL:function(row){//删除指定行,并将其之上所有的cell下移
this.wall.splice(row,1);//只删除一行
this.wall.unshift([]);//顶部压入一个新空行
//从row行开始,向上遍历每一行
for(var r=row;r>0;r--){
// 从0开始遍历当前行每个格
for(var c=0;c<this.CN;c++){
// 如果当前格有效
if(this.wall[r][c]){
// 将当前格的row++
this.wall[r][c].row++;
}
}
}
},
//九、判断游戏是否结束
isGameOver:function(){
//获取nextShape中所有cell,保存在cells中
var cells=this.nextShape.cells;
//遍历cells中每个cell
for(var i=0;i<cells.length;i++){
//取出wall中和当前cell相同row,col位置的格子
var cell=this.wall[cells[i].row][cells[i].col];
//只要碰到有效的
if(cell){
return true;
}
}//for的结束
return false;
},
//八、
paintNext:function(){
var cells=this.nextShape.cells;
for(var i=0;i<cells.length;i++){
//先将当前cell的row+1,存在r变量中
var r=cells[i].row+1;
//再将当前cell的col+11,存在c变量中
var c=cells[i].col+11;
var x=c*this.CSIZE+this.OFFSET_X;
var y=r*this.CSIZE+this.OFFSET_y;
var img=new Image();
img.src=cells[i].img;
img.style.left=x+"px";
img.style.top=y+"px";
this.pg.appendChild(img);
}
},
//七、
paintWall:function(){
//七、遍历二维数组wall中每个格
for(var r=0;r<this.RN;r++){
for(var c=0;c<this.CN;c++){
var cell=this.wall[r][c];
// 如果当前cell有效
if(cell){
var x=cell.col*this.CSIZE+this.OFFSET_X;
var y=cell.row*this.CSIZE+this.OFFSET_y;
var img=new Image();
img.src=cell.img;
img.style.left=x+"px";
img.style.top=y+"px";
this.pg.appendChild(img);
}
}
}
},
//六、把所有停止下落的方块放入wall中
landIntoWall:function(){
//遍历当前图形中每个cells
// 每遍历一个cell
// 就将cell放入wall中相同row,col的位置:this.wall[?][?]=?
var cells=this.currShape.cells;
for(var i=0;i<cells.length;i++){
this.wall[cells[i].row][cells[i].col]=cells[i];
}
},
//五、//判断是否继续可以下落
canDrop:function(){
//遍历当前currShape中的cells
// 只要发现任意一个的cell的row==RN-1
// 就返回false
//
var cells=this.currShape.cells;
for(var i=0;i<cells.length;i++){
if(cells[i].row==this.RN-1){
return false;
}//七、wall中,当前cell的下一行位置有效
if(this.wall[cells[i].row+1][cells[i].col]){
return false
}
}//遍历结束后
//七、currShape中,任意一个cell的下方有wall中的cell
return true;
},
//4、随机生成一种图形--二
randomShape:function(){
switch(parseInt(Math.random()*7)){
case 0: return new O();
case 1: return new L();
case 2: return new J();
case 3: return new S();
case 4: return new Z();
case 5: return new I();
case 6: return new T();
}
},
//3
paintShape:function(){//3、专门绘制当前图形的方法
var cells=this.currShape.cells;
for(var i=0;i<cells.length;i++){
var x=cells[i].col*this.CSIZE+this.OFFSET_X;
var y=cells[i].row*this.CSIZE+this.OFFSET_y;
var img=new Image();
img.src=cells[i].img;
img.style.left=x+"px";
img.style.top=y+"px";
this.pg.appendChild(img);
}
},//paintShape的结束
}//tetris结束
window.onload=function(){
tetris.init();
}

  2、shapes.js

function Cell(row,col,img){
this.row=row;
this.col=col;
this.img=img;
//三下落
if(!Cell.prototype.drop){
Cell.prototype.drop=function(){
this.row++;
}
}
if(!Cell.prototype.moveR){//十一
Cell.prototype.moveR=function(){
this.col++;
}
}
if(!Cell.prototype.moveL){//十一
Cell.prototype.moveL=function(){
this.col--;
}
}
}
//十四、下落的各种变化状态
function State(r0,c0,r1,c1,r2,c2,r3,c3){
//第0个cell相对于参照cell的下标偏移量
this.r0=r0;
this.c0=c0;
//第1个cell相对于参照cell的下标偏移量
this.r1=r1;
this.c1=c1;
//第2个cell相对于参照cell的下标偏移量
this.r2=r2;
this.c2=c2;
//第3个cell相对于参照cell的下标偏移量
this.r3=r3;
this.c3=c3;
}
function Shape(img,orgi){
this.img=img;
this.states=[];//十四、保存每个图形不同状态的数组
this.orgi=orgi;//十四、以它为固定不变的参照点,去旋转变形,就是数组states的下标
this.statei=0;//默认所有图形的最初状态都是0
//三
if(!Shape.prototype.drop){
Shape.prototype.drop=function(){
//遍历当前对象的cells中的每个cell对象
// 调用当前cell对象的drop方法
for(var i=0;i<this.cells.length;i++){
this.cells[i].drop();
}
}
}
if(!Shape.prototype.moveR){//十一
Shape.prototype.moveR=function(){
//遍历当前对象的cells中的每个cell对象
for(var i=0;i<this.cells.length;i++){
// 调用当前cell对象的drop方法
this.cells[i].moveR();
}
}
}
if(!Shape.prototype.moveL){//十一
Shape.prototype.moveL=function(){
//遍历当前对象的cells中的每个cell对象
for(var i=0;i<this.cells.length;i++){
// 调用当前cell对象的drop方法
this.cells[i].moveL();
}
}
}
//十五
if(!Shape.prototype.rotateR){
Shape.prototype.rotateR=function(){
//if(Object.getPrototypeOf(this)!=O.prototype){
if(this.constructor!=O){
this.statei++;
this.statei>=this.states.length&&(this.statei=0);
//获得下一个状态对象
var state=this.states[this.statei];
var orgr=this.cells[this.orgi].row;
var orgc=this.cells[this.orgi].col;
//遍历当前图形中的每个cell
//按state中偏移量,设置每个cell的新位置
for(var i=0;i<this.cells.length;i++){
this.cells[i].row=orgr+state["r"+i];
this.cells[i].col=orgc+state["c"+i];
}//for的结束
}//if的结束
}//function的结束
}//if的结束
if(!Shape.prototype.rotateL){
Shape.prototype.rotateL=function(){
//if(Object.getPrototypeOf(this)!O.prototype){
if(this.constructor!=O){
this.statei--;
this.statei<0&&(this.statei=this.states.length-1);
//获得下一个状态对象
var state=this.states[this.statei];
var orgr=this.cells[this.orgi].row;
var orgc=this.cells[this.orgi].col;
//遍历当前图形中的每个cell
//按照state中偏移量,设置每个cell的心位置
for(var i=0;i<this.cells.length;i++){
this.cells[i].row=orgr+state["r"+i];
this.cells[i].col=orgc+state["c"+i];
}//for的结束
}//if的结束
}//function的结束
}//if的结束
}//function Shape(img,orgi)的结束
//二
function O(){//1
Shape.call(this,"img/O.png");
if(!Shape.prototype.isPrototypeOf(O.prototype)){
Object.setPrototypeOf(O.prototype,Shape.prototype);//继承
}
this.cells=[
new Cell(0,4,this.img),new Cell(0,5,this.img),
new Cell(1,4,this.img),new Cell(1,5,this.img)
];
}
function T(){//2
Shape.call(this,"img/T.png",1);
if(!Shape.prototype.isPrototypeOf(T.prototype)){
Object.setPrototypeOf(T.prototype,Shape.prototype);//继承
}
this.cells=[
new Cell(0,3,this.img),new Cell(0,4,this.img),
new Cell(0,5,this.img),new Cell(1,4,this.img)
];
//十四
this.states[0]=new State(0,-1, 0,0, 0,1, 1,0);
this.states[1]=new State(-1,0, 0,0, 1,0, 0,-1);
this.states[2]=new State(0,1, 0,0, 0,-1, -1,0);
this.states[3]=new State(1,0, 0,0, -1,0, 0,1);
// [0] [1] [2] [3]
} function I(){//3
Shape.call(this,"img/I.png",1);
if(!Shape.prototype.isPrototypeOf(I.prototype)){
Object.setPrototypeOf(I.prototype,Shape.prototype);//继承
}
this.cells=[
new Cell(0,3,this.img),new Cell(0,4,this.img),
new Cell(0,5,this.img),new Cell(0,6,this.img)
];
this.states[0]=new State(0,-1, 0,0, 0,1, 0,2);
// [0] [1] [2] [3]
this.states[1]=new State(-1,0, 0,0, 1,0, 2,0);
}
function S(){//4
Shape.call(this,"img/S.png",3);
if(!Shape.prototype.isPrototypeOf(S.prototype)){
Object.setPrototypeOf(S.prototype,Shape.prototype);//继承
}
this.cells=[
new Cell(0,4,this.img),new Cell(0,5,this.img),
new Cell(1,3,this.img),new Cell(1,4,this.img)
];
//十四
this.states[0]=new State(-1,0, -1,1, 0,-1, 0,0);
this.states[1]=new State(0,1, 1,1, -1,0, 0,0);
// [0] [1] [2] [3]
}
function Z(){//5
Shape.call(this,"img/Z.png",1);
if(!Shape.prototype.isPrototypeOf(Z.prototype)){
Object.setPrototypeOf(Z.prototype,Shape.prototype);//继承
}
this.cells=[
new Cell(0,3,this.img),new Cell(0,4,this.img),
new Cell(1,4,this.img),new Cell(1,5,this.img)
];
this.states[0]=new State(0,-1, 0,0, 1,0, 1,1);
this.states[1]=new State(-1,0, 0,0, 0,-1, 1,-1);
// [0] [1] [2] [3]
}
function L(){//6
Shape.call(this,"img/L.png",1);
if(!Shape.prototype.isPrototypeOf(L.prototype)){
Object.setPrototypeOf(L.prototype,Shape.prototype);//继承
}
this.cells=[
new Cell(0,3,this.img),new Cell(0,4,this.img),
new Cell(0,5,this.img),new Cell(1,3,this.img)
];
this.states[0]=new State(0,-1, 0,0, 0,1, 1,-1);
this.states[1]=new State(-1,0, 0,0, 1,0, -1,-1);
this.states[2]=new State(0,1, 0,0, 0,-1, -1,1);
this.states[3]=new State(1,0, 0,0, -1,0, 1,1);
// [0] [1] [2] [3]
}
function J(){//7
Shape.call(this,"img/J.png",1);
if(!Shape.prototype.isPrototypeOf(J.prototype)){
Object.setPrototypeOf(J.prototype,Shape.prototype);//继承
}
this.cells=[
new Cell(0,3,this.img),new Cell(0,4,this.img),
new Cell(0,5,this.img),new Cell(1,5,this.img)
];
this.states[0]=new State(-1,0, 0,0, 1,-1, 1,0);
this.states[1]=new State(0,1, 0,0, -1,-1, 0,-1);
this.states[2]=new State(1,0, 0,0, -1,1, -1,0);
this.states[3]=new State(0,-1, 0,0, 1,1, 0,1);
// [0] [1] [2] [3]
}

 效果:

JAVASCRIPT实现网页版:俄罗斯方块的更多相关文章

  1. Javascript之网页版待办事项

    本文使用原生JS实现站点 http://www.todolist.cn/ 的基本功能. 其中页面的HTML布局和CSS样式取用原站,JS部分为自己编写. 效果图 完整代码 HTML.JS部分 < ...

  2. javascript实现移动端网页版阅读器

    现在手机上的文本阅读app已经非常丰富,良好的阅读体验与海量的书库常常令我感到无比兴奋. 我想到8年前用一点几寸屏幕的mp3看电子书的情景,顿生一种淡淡的温馨.再久远一些,小的时候,我也经常和小伙伴们 ...

  3. 利用 JavaScript SDK 部署网页版“Facebook 登录”

    facebook开发者平台https://developers.facebook.com/ 利用 JavaScript SDK 部署网页版“Facebook 登录” 通过采用 Javascript 版 ...

  4. JavaScript之简易http接口测试工具网页版

    简易http接口测试工具网页版,支持get.post请求,支持json格式消息体,form表单暂不支持. httpClient.html <!DOCTYPE html> <html ...

  5. jQuery实践-网页版2048小游戏

    ▓▓▓▓▓▓ 大致介绍 看了一个实现网页版2048小游戏的视频,觉得能做出自己以前喜欢玩的小游戏很有意思便自己动手试了试,真正的验证了这句话-不要以为你以为的就是你以为的,看视频时觉得看懂了,会写了, ...

  6. 分享:计算机图形学期末作业!!利用WebGL的第三方库three.js写一个简单的网页版“我的世界小游戏”

    这几天一直在忙着期末考试,所以一直没有更新我的博客,今天刚把我的期末作业完成了,心情澎湃,所以晚上不管怎么样,我也要写一篇博客纪念一下我上课都没有听,还是通过强大的度娘完成了我的作业的经历.(当然作业 ...

  7. 网页版电子表格控件tmlxSpreadsheet免费下载地址

    tmlxSpreadsheet 是一个由JavaScript 和 PHP 写成的电子表格控件(包含WP插件, Joomla插件等等).. 程序员可以容易的添加一个类似Excel功能的,可编辑的表格功能 ...

  8. H5版俄罗斯方块(2)---游戏的基本框架和实现

    前言: 上文中谈到了H5版俄罗斯方块的需求和目标, 这次要实现一个可玩的版本. 但饭要一口一口吃, 很多东西并非一蹴而就. 本文将简单实现一个可玩的俄罗斯方块版本. 下一步会引入AI, 最终采用coc ...

  9. 基于HTML5的捕鱼达人游戏网页版

    之前给大家分享了html5实现的水果忍者,愤怒的小鸟,中国象棋游戏.今天给大家分享一款捕鱼达人(fishjoy)网页版游戏的源码.可以在线玩也可以下载到本地.它使用html5技术和javascript ...

随机推荐

  1. java session 详解

    原网址:http://blog.sina.com.cn/s/blog_670b6d880101deff.html 一.术语session 在我的经验里,session这个词被滥用的程度大概仅次于tra ...

  2. 云计算之路-阿里云上:结合IIS日志分析“黑色30秒”问题

    在昨天针对“黑色30秒”问题的分析中,我们猜测Requests Queued上升是由于正在处理的请求出不去(到达不了客户端).今天我们结合IIS日志验证这个猜测. IIS日志中有一个重要的指标——ti ...

  3. LocationManager使用细节

    在使用系统的LocationManager请求地理位置的时候,请特别注意一个很小的细节,调用 requestLocationUpdates 以后,请记得[自己]设置一个timeout值,否则在某些情况 ...

  4. Windows Azure Affinity Groups (3) 修改虚拟网络地缘组(Affinity Group)的配置

    <Windows Azure Platform 系列文章目录> 本文介绍的是国内使用世纪互联运维的Azure China 在笔者之前的文章中,我们知道现在微软官方不建议使用Affinity ...

  5. 简单的使用ehcache

    之前一直感觉缓存是高上大的东西,没有心思去研究.做了之后发现,简单的使用还是很容易的.这里记录ehcache在jfinal中的简单使用. 1.ehcahe简介 EhCache 是一个纯Java的进程内 ...

  6. 基于HT for Web的Web SCADA工控移动应用

    在电力.油田燃气.供水管网等工业自动化领域Web SCADA的概念已经提出了多年,早先年的Web SCADA前端技术大部分还是基于Flex.Silverlight甚至Applet这样的重客户端方案,在 ...

  7. qml基础学习 模型视图(一)

    一.理解qml模型和视图 qt的发展是迅速的,虽然在每一个release版本中或多或少都有bug,但是作为一个庞大的gui库,no,应该说是一个开发框架开说,qt已经算是做的相当好.qml部分是qt4 ...

  8. SQLite中文排序

    定义一个类: using System.Data.SQLite; namespace DAL { /// <summary> /// SQLite中文排序 /// </summary ...

  9. iOS阶段学习第31天笔记(UINavigationBar介绍)

    iOS学习(UI)知识点整理 一.UINavigationBar 的介绍 1)概念:UINavigationBar 是用于定义导航栏按钮的一个类对象 2)在使用UINavigationBar之前必须先 ...

  10. java输出MYSQL数据库里面的数据最简单的实例

    import java.sql.*; public class JDBCExample { static final String JDBC_DRIVER = "com.mysql.jdbc ...