俄罗斯方块方块是小时候的一个回忆,从最开始的掌上的黑白游戏机,到电视游戏机,到电脑,无不有它的痕迹,今天我们来一起重温它的一种实现方法,也算是整理一下我的思路吧......
HTML+CSS+JS实现俄罗斯方块完整版,素材只有图片,想要的下载图片按提示名字保存,css中用的时候注意路径!!主要在JS中!JS附有详细注释
效果:
按键提示:[键盘按键]
素材:图片名字与代码里对应
1、背景图片:tetris.png
2、失败时候的弹出框图片:game-over.png
3、七种色彩小方块图片:
HTML代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>俄罗斯方块 — 经典完整版</title> <link rel="stylesheet" href="css/tetris.css"/> <script src="/UploadFiles/2021-04-02/shapes.js">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"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(.*""); 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["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代码编写的网页版俄罗斯方块。希望大家喜欢。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 【雨果唱片】中国管弦乐《鹿回头》WAV
- APM亚流新世代《一起冒险》[FLAC/分轨][106.77MB]
- 崔健《飞狗》律冻文化[WAV+CUE][1.1G]
- 罗志祥《舞状元 (Explicit)》[320K/MP3][66.77MB]
- 尤雅.1997-幽雅精粹2CD【南方】【WAV+CUE】
- 张惠妹.2007-STAR(引进版)【EMI百代】【WAV+CUE】
- 群星.2008-LOVE情歌集VOL.8【正东】【WAV+CUE】
- 罗志祥《舞状元 (Explicit)》[FLAC/分轨][360.76MB]
- Tank《我不伟大,至少我能改变我。》[320K/MP3][160.41MB]
- Tank《我不伟大,至少我能改变我。》[FLAC/分轨][236.89MB]
- CD圣经推荐-夏韶声《谙2》SACD-ISO
- 钟镇涛-《百分百钟镇涛》首批限量版SACD-ISO
- 群星《继续微笑致敬许冠杰》[低速原抓WAV+CUE]
- 潘秀琼.2003-国语难忘金曲珍藏集【皇星全音】【WAV+CUE】
- 林东松.1997-2039玫瑰事件【宝丽金】【WAV+CUE】