废话都就不多说了,直接贴代码
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>JS俄罗斯方块-练习</title> <style type="text/css"> body { margin-left:auto; margin-right:auto; width:310px; } .leftFloat { float: left;; } #panel table { border-collapse: collapse; } #panel table td { border: 1px solid #bbbbbb; width: 20px; height: 20px; font-size: 0; line-height: 0; overflow: hidden; } #panel table .actived { background-color: #343434; } #boxPanel table { border-collapse: collapse; } #boxPanel table td { border: 1px solid #bbbbbb; width: 10px; height: 10px; font-size: 0; line-height: 0; overflow: hidden; } #boxPanel table .actived { background-color: #343434; } </style> <script type="text/javascript"> /*程序入口*/ var main = new function(){ var control = new Control(); var isPause = false; /*开始*/ window.onload = function(){ control.init(); /*start*/ document.getElementById("btnStart").onclick = function(){ control.start(isPause); main.showInfo(); isPause = false; this.disabled = true; document.getElementById("btnPause").disabled = false; } /* 暂停*/ document.getElementById("btnPause").onclick = function() { isPause = true; control.pause(); this.disabled = true; document.getElementById("btnStart").disabled = false; } }; /*游戏结束*/ this.gameOver = function(){ GlobalData.SPEED = 250; document.getElementById("btnStart").disabled = false; document.getElementById("btnPause").disabled = true; }; /*增加得分*/ this.addScore = function(lineCount) { var score = 0; if(lineCount > 0) { switch(lineCount) { case 1: score = 100; break; case 2: score = 300; break; case 3: score = 600; break; case 4: score = 1000; break; } control.userData.addScore(score); this.showInfo(); } } /*显示成绩*/ this.showInfo = function(){ document.getElementById("score").innerHTML = control.userData.score; document.getElementById("level").innerHTML = control.userData.level; } } /*用户数据*/ function UserData(levelUp){ this.score = 0; this.level = 1; this.levelUp = levelUp; /*增加得分*/ this.addScore = function(score) { var levelData = this._getLevelData(this.level); this.score += score; if(this.score >= levelData.score) { this.level ++; GlobalData.SPEED = levelData.speed; this.levelUp(); } } /*取得关卡对应的得分及速度*/ this._getLevelData = function(level){ var data = {}; data.score = 5000 * level; if(level < 6) { data.speed = 250 - (level - 1) * 50; } else { data.speed = 50 - (level - 5) * 2; if(data.speed <= 0) data.speed = 2; } return data; } } /*公共参数*/ var GlobalData = new function(){ this.ROWS = 20; /*面板行数*/ this.COLS = 10; /*面板列数*/ this.SIZE = 20; /*方块大小*/ this.SPEED = 250; /*速度*/ this.WORK_THREAD = null; /*定时器*/ } /*方块类型*/ var BoxType = new function(){ this.I = 0; this.J = 1; this.L = 2; this.O = 3; this.S = 4; this.Z = 5; this.T = 6; this.V = 7; this.SIZE = 8; } /*move box的所有形状*/ var MoveBoxsStatus = new function(){ var i0 = {"offset":"2,0","pos":"0,0,1,0 0,0,1,0 0,0,1,0 0,0,1,0"}; var i1 = {"offset":"0,1","pos":"0,0,0,0 1,1,1,1 0,0,0,0 0,0,0,0"}; var j0 = {"offset":"0,0","pos":"0,1,0 0,1,0 1,1,0"}; var j1 = {"offset":"0,0","pos":"1,0,0 1,1,1 0,0,0"}; var j2 = {"offset":"1,0","pos":"0,1,1 0,1,0 0,1,0"}; var j3 = {"offset":"0,0","pos":"1,1,1 0,0,1 0,0,0"}; var l0 = {"offset":"1,0","pos":"0,1,0 0,1,0 0,1,1"}; var l1 = {"offset":"0,1","pos":"0,0,0 1,1,1 1,0,0"}; var l2 = {"offset":"0,0","pos":"1,1,0 0,1,0 0,1,0"}; var l3 = {"offset":"0,0","pos":"0,0,1 1,1,1 0,0,0"}; var o0 = {"offset":"0,0","pos":"1,1 1,1"}; var s0 = {"offset":"0,0","pos":"0,1,1 1,1,0 0,0,0"}; var s1 = {"offset":"1,0","pos":"0,1,0 0,1,1 0,0,1"}; var z0 = {"offset":"0,0","pos":"1,1,0 0,1,1 0,0,0"}; var z1 = {"offset":"0,0","pos":"0,1,0 1,1,0 1,0,0"}; var t0 = {"offset":"0,1","pos":"0,0,0 1,1,1 0,1,0"}; var t1 = {"offset":"0,0","pos":"0,1,0 1,1,0 0,1,0"}; var t2 = {"offset":"0,0","pos":"0,1,0 1,1,1 0,0,0"}; var t3 = {"offset":"1,0","pos":"0,1,0 0,1,1 0,1,0"}; var v0 = {"offset":"0,0","pos":"1,1 0,1"}; var v1 = {"offset":"0,0","pos":"0,1 1,1"}; var v2 = {"offset":"0,0","pos":"1,0 1,1"}; var v3 = {"offset":"0,0","pos":"1,1 1,0"}; this.oriPanels = function(type) { var panels = []; switch(type) { case BoxType.I: panels.push(i0); panels.push(i1); break; case BoxType.J: panels.push(j0); panels.push(j1); panels.push(j2); panels.push(j3); break; case BoxType.L: panels.push(l0); panels.push(l1); panels.push(l2); panels.push(l3); break; case BoxType.O: panels.push(o0); break; case BoxType.S: panels.push(s0); panels.push(s1); break; case BoxType.Z: panels.push(z0); panels.push(z1); break; case BoxType.T: panels.push(t0); panels.push(t1); panels.push(t2); panels.push(t3); break; case BoxType.V: panels.push(v0); panels.push(v1); panels.push(v2); panels.push(v3); break; } return panels; } } /*命令*/ var Cmd = new function(){ this.RIGHT = 39; this.DOWN = 40; this.UP = 38; this.LEFT = 37; this.ENTER = 13; this.SPACE = 32; } /*根据postion取得对应的box id*/ function getBoxId(pid,pos) { return pid + "_box_" +pos.x +"_" + pos.y; } /*根据box id取得box*/ function getBox(id) { return document.getElementById(id); } /*设置box的class*/ function setBoxClassById(id , className) { var box = getBox(id); if(!className) { className = ""; } if(box) { box.className = className; } } function setBoxClassByPos(pid , pos , className) { var boxId = getBoxId(pid , pos); setBoxClassById(boxId , className); } /*控制*/ function Control(){ var me = this; this.panel = new Panel(); this.moveBoxCtrl = new MoveBoxCtrl(); /*升级,清空并加速*/ this.levelUp = function() { me.moveBoxCtrl.clear(); me._startTimer(); } this.userData = new UserData(this.levelUp); /*初始化*/ this.init = function(){ this.panel.init("panel",GlobalData.ROWS,GlobalData.COLS); this.panel.init("boxPanel",4,4); this.moveBoxCtrl.gameOver = this.gameOver; }; /*开始*/ this.start = function(isPause){ if(!isPause) { this.moveBoxCtrl.clear(); this.moveBoxCtrl.create(); this.moveBoxCtrl.createPreviewBox(); } this.addEvent(document , "keydown" , this.moveBoxCmd); this._startTimer(); }; /*计时器开始*/ this._startTimer = function() { if(GlobalData.workThread) { clearInterval(GlobalData.workThread); } GlobalData.workThread = setInterval(function(){ me.boxMove(); } , GlobalData.SPEED); } /**/ this.moveBoxCmd = function(ev) { var evt = window.event || ev; // console.log(evt.keyCode); me.moveBoxCtrl.setCmd(evt.keyCode); }; /*块移动*/ this.boxMove = function () { me.moveBoxCtrl.move(); }; /*暂停*/ this.pause = function() { if(GlobalData.workThread) { clearInterval(GlobalData.workThread); GlobalData.workThread = null; } me.delEvent(document, "keydown" , me.moveBoxCmd); }; /*game over*/ this.gameOver = function(){ me.pause(); main.gameOver(); }; /*添加事件*/ this.addEvent = function(target,type,func) { if(target.addEventListener) { target.addEventListener(type , func , false); } else if(target.attachEvent) { target.attachEvent("on" + type , func); } else { target["on" + type] = func; } }; /*移除事件*/ this.delEvent = function(target,type,func) { if(target.removeEventListener) { target.removeEventListener(type , func , false); } else if(target.detachEvent) { target.detachEvent("on" + type , func); } else { delete target["on" + type]; } }; } /*游戏面板*/ function Panel(){} Panel.prototype.init = function(pid,rows,cols){ var html = []; html.push("<table>"); for(var i = 0 ; i < rows ; i++) { html.push("<tr>"); for(var j= 0; j < cols ; j++) { html.push(‘<td id ="‘+getBoxId(pid,new Position(j, i))+‘"></td>‘); } html.push("</tr>"); } document.getElementById(pid).innerHTML = html.join(""); }; /*停止移动的方块*/ function StopMoveBoxs(){ this.pos = [];/*停止移动的方块*/ this.lines = []; /*添加pos*/ this.addPos = function(pos){ this._insertLine(pos); this.show(); this._clearLine(); this.show(true); } /*往行中插入*/ this._insertLine = function(pos) { if(this.lines.length == 0) this._initLines(); var tempPos; var tempLine; for(var i = 0; i < pos.length ; i++) { tempPos = pos[i]; tempLine = this.lines[tempPos.y]; tempLine.insert(tempPos); } this._getPos(); } /*清空满足条件的一行*/ this._clearLine = function() { var clearLine = []; var tempLine; for(var i = 0; i <this.lines.length ; i++) { tempLine = this.lines[i]; if(tempLine.canClear()) { clearLine.push(tempLine); } } if(clearLine.length > 0) { for(var j = 0; j < clearLine.length ; j++) { tempLine = clearLine[j]; tempLine.clear(); for(var k = tempLine.row - 1 ; k >= 0 ; k -- ){ this._swapLines(k , k + 1); } } this._getPos(); main.addScore(clearLine.length); } } /*交换行*/ this._swapLines = function(line , toLine){ var tempLine = this.lines[line]; this.lines[toLine] = tempLine; tempLine.setRow(toLine); this.lines[line] = new StopMoveBoxsLine(line); } /*显示move box*/ this.show = function(isShow){ var className = isShow?"actived":""; for(var i = 0; i < this.pos.length ;i++) { setBoxClassByPos("panel",this.pos[i], className); } }; /*初始化行*/ this._initLines = function() { for(var i = 0 ; i < GlobalData.ROWS; i ++){ this.lines.push(new StopMoveBoxsLine(i)); } } /*取得pos*/ this._getPos = function(){ this.pos = []; for(var i = 0; i < this.lines.length ; i++) { if(!this.lines[i].isEmpty()) { this.pos = this.pos.concat(this.lines[i].pos); } } } /*清空*/ this.clear = function(){ this.show(); this.pos = []; this.lines = []; } } /*不能移动的行*/ function StopMoveBoxsLine(row){ this.pos = []; this.row = row; } /*插入*/ StopMoveBoxsLine.prototype.insert = function(pos) { if(this.isEmpty()) { this.pos.push(pos); } else { for(var i = 0; i < this.pos.length ; i++) { var compareResult = pos.compare(this.pos[i]); if(compareResult < 1) { if(compareResult == -1) { var leftArr = this.pos.slice(0 , i); leftArr.push(pos); var rightArr = this.pos.slice(i); this.pos = leftArr.concat(rightArr); } break; } } if(i >= this.pos.length) { this.pos.push(pos); } } }
/*设置行*/ StopMoveBoxsLine.prototype.setRow = function(row) { this.row = row; for(var i = 0; i < this.pos.length ; i++) { this.pos[i].y = row; } } /*是否为空*/ StopMoveBoxsLine.prototype.isEmpty = function(){ return this.pos.length == 0; } /*返回是否可以被清除*/ StopMoveBoxsLine.prototype.canClear = function(){ return this.pos.length == GlobalData.COLS; } /*清除*/ StopMoveBoxsLine.prototype.clear = function(){ this.pos = []; } /*移动的方块*/ function MoveBoxCtrl(){ this.previewBox = null; this.box = null; this.stopMoveBoxs = new StopMoveBoxs(); this.gameOver; /*生成一个形状的方块*/ this.create = function(){ var tempBox = this._randomCreateBox("panel"); this.box = tempBox; this.box.show(true); }; /*随机生成一个方块*/ this._randomCreateBox = function(pid){ var type = parseInt(Math.random() * BoxType.SIZE); var status = parseInt(Math.random() * 4); var tempBox = new MoveBox(pid , type , status , this.stopMoveBoxs); tempBox.init(); return tempBox; } /*方块预览*/ this.createPreviewBox = function(){ this.previewBox = this._randomCreateBox("boxPanel"); this.previewBox.show(true); } /*旋转*/ this.rotation = function(){ this.box.rotation(); }; /*命令*/ this.setCmd = function(code) { switch(code) { case Cmd.LEFT: case Cmd.RIGHT: this.box.move(code); break; case Cmd.ENTER: case Cmd.UP: this.box.rotation(); break; case Cmd.SPACE: this.box.telepote(); this.next(); break; } }; this.next = function(){ this.previewBox.show(); this.box = this.previewBox; this.box.pid = "panel"; this.box.translate(); if(!this.box.isPosCanChange(this.box.pos)) { // game over this.stopMoveBoxs.addPos(this.box.pos); console.log("game over"); this.gameOver(); } else { this.createPreviewBox(); } } /*移动*/ this.move = function(){ var moveStatus = this.box.move(Cmd.DOWN); // 无法移动了,也就是靠底了之类的 if(moveStatus == 1) { this.stopMoveBoxs.addPos(this.box.pos); this.next(); } this.box.canSetCmd = true; }; this.clear = function(){ this.stopMoveBoxs.clear(); } } /*旋转帮助*/ function RotationUtil(moveBox) { this.moveBox = moveBox; this.panels = []; } /*旋转至*/ RotationUtil.prototype.rotationTo = function(pid , status){ if(this.panels.length == 0) this._initPanels(); var realPanel = this._realPosPanel(); // 设置movebox状态 if(status > this.panels.length - 1 ) status = 0; this.moveBox.status = status; //取得面板 var realPos = this._getRealPos(realPanel); var canChange = this.moveBox.isPosCanChange(realPos); if(canChange) { // this.moveBox.show(pid); this.moveBox.pos = realPos; // this.moveBox.show(pid , true); } } /*旋转*/ RotationUtil.prototype.rotation = function(){ if(this.panels.length == 0) this._initPanels(); var realPanel = this._realPosPanel(); // 设置movebox状态 var status = this.moveBox.status + 1; if(status > this.panels.length - 1 ) status = 0; this.moveBox.status = status; //取得面板 var realPos = this._getRealPos(realPanel); var canChange = this.moveBox.isPosCanChange(realPos); if(canChange) { this.moveBox.show(); this.moveBox.pos = realPos; this.moveBox.show(true); } else { status = status - 1; if(status < 0) status = this.panels.length - 1; this.moveBox.status = status; } }; /*初始化面板组*/ RotationUtil.prototype._initPanels = function(){ this.panels = MoveBoxsStatus.oriPanels(this.moveBox.type); }; /*取得对应形状的pos列表*/ RotationUtil.prototype._getPanel = function(){ if(this.panels.length == 0) this._initPanels(); if(this.moveBox.status >= this.panels.length) this.moveBox.status = 0; var panel = this.panels[this.moveBox.status]; if(!panel.poslist) { var list = panel.pos.split(" "); for(var i = 0 ; i <list.length ; i++) { var childList = list[i].split(","); list[i]= childList; } panel.poslist = list; } if(!panel.posResult) { var list = panel.poslist; var result = []; for(var row = 0; row < list.length; row ++) { var rows = list[row]; for(var col = 0; col <rows.length ; col ++) { if(rows[col] == "1") { result.push(new Position(col , row)); } } } panel.posResult = result; } return panel; }; /*根据当前move box生成对应的面板*/ RotationUtil.prototype._realPosPanel = function(){ var panel = this._getPanel(); var info = this.moveBox.boxInfo(); var list = panel.poslist; var offset = panel.offset.split(","); var oriPoint = new Position(info.leftX - offset[0] , info.topY - offset[1]); var realPanel = []; for(var i = 0; i < list.length ; i++) { var row = list[i]; var realRow = []; for(var j = 0 ; j < row.length ; j ++) { realRow.push(new Position(oriPoint.x + j , oriPoint.y + i)); } realPanel.push(realRow); } return realPanel; } /*取得真实pos*/ RotationUtil.prototype._getRealPos = function(realPanel) { var panel = this._getPanel(); var pos = panel.posResult; var realPos = []; for(var i = 0 ; i < pos.length ; i++) { var tempPos = realPanel[pos[i].y][pos[i].x]; realPos.push(new Position(tempPos.x , tempPos.y)); } return realPos; } /*移动的方块*/ function MoveBox(pid , type , status , stopMoveBoxs){ this.pid = pid; this.type = type; this.status = status; this.pos = []; this.rotationUtil = new RotationUtil(this); this.stopMoveBoxs = stopMoveBoxs; this.canSetCmd = true; } MoveBox.prototype.init = function(){ this.rotationUtil.rotationTo(this.pid , this.status); if(this.pid == "panel") this.translate(); }; /*旋转*/ MoveBox.prototype.rotation = function(){ if(!this.canSetCmd) return; this.rotationUtil.rotation(); }; /* 移动*/ MoveBox.prototype.move = function(dir){ var result = 0; if(!this.canSetCmd) return result; var tempPos = []; var isDown = false; for(var i= 0; i < this.pos.length ; i++){ tempPos.push(new Position(this.pos[i].x , this.pos[i].y)); switch(dir) { case Cmd.LEFT: tempPos[i].x --; break; case Cmd.RIGHT: tempPos[i].x ++; break; case Cmd.DOWN: this.canSetCmd = false; isDown = true; tempPos[i].y ++; break; } } if(this.isPosCanChange(tempPos)) { this.show(); this.pos = tempPos; this.show(true); result = 2; } else if(isDown) { result = 1; } return result; }; /* 瞬移*/ MoveBox.prototype.telepote = function(){ if(!this.canSetCmd) return; this.show(); var lines = this.stopMoveBoxs.lines; var prePos; var tempPos = this.pos; while(true) { prePos = tempPos; tempPos = []; for(var i = 0; i < prePos.length ; i++) { tempPos.push(new Position(prePos[i].x , prePos[i].y + 1)); } if(!this.isPosCanChange(tempPos)) { break; } } this.stopMoveBoxs.addPos(prePos); }; /*平移*/ MoveBox.prototype.translate = function(){ var info = this.boxInfo(); var offset = parseInt((GlobalData.COLS - info.width)/2); for(var i = 0; i < this.pos.length ; i++) { this.pos[i].x += offset; } this.show(true); }; /*显示move box*/ MoveBox.prototype.show = function(isShow){ var className = isShow?"actived":""; for(var i = 0; i < this.pos.length ;i++) { setBoxClassByPos(this.pid , this.pos[i], className); } }; /*判断提供的位置是否合法*/ MoveBox.prototype.isPosCanChange = function(pos) { var tempPos; for(var i = 0; i< pos.length ; i++) { tempPos = pos[i]; if(tempPos.x < 0 || tempPos.x >= GlobalData.COLS) return false; if(tempPos.y >= GlobalData.ROWS) return false; for(var j = 0 ; j < this.stopMoveBoxs.pos.length; j ++) { if(tempPos.x == this.stopMoveBoxs.pos[j].x && tempPos.y == this.stopMoveBoxs.pos[j].y) return false; } } return true; } /*move box info*/ MoveBox.prototype.boxInfo = function() { var leftX = -1; var rightX = -1; var topY = -1; var bottomY = -1; for(var i = 0 ; i < this.pos.length; i ++) { var pos = this.pos[i]; if(leftX < 0 || pos.x < leftX) leftX = pos.x; if(topY < 0 || pos.y < topY) topY = pos.y; if(pos.x > rightX) rightX = pos.x; if(pos.y > bottomY) bottomY = pos.y; } if(leftX < 0) leftX = 0; if(topY < 0) topY = 0; if(rightX < 0) rightX = 0; if(bottomY < 0) bottomY = 0; var width = rightX - leftX; if(rightX!=0) width = width + 1; var height = bottomY - topY; if(bottomY!=0) height = height + 1; return {"leftX":leftX , "topY":topY , "width":width , "height":height}; } /*x,y坐标*/ function Position(x,y,value){ this.x = 0; this.y = 0; this.value = 0; if(arguments.length >= 1) this.x = x; if(arguments.length >= 2) this.y = y; if(arguments.length >= 3) this.value = value; } /*比较大小*/ Position.prototype.compare = function(pos) { var result = 0; if(this.y > pos.y) { result = 1; } else if(this.y == pos.y){ if(this.x > pos.x) { result = 1; } else if(this.x == pos.x){ result = 0; } else { result = -1; } } else { result = -1; } return result; } </script> </head> <body> <p>成绩:<span id="score" style="margin-right:20px">0</span>等级:<span id="level">1</span></p> <div id="panel" style="margin-right:10px; margin-bottom: 10px;" class="leftFloat"></div> <div id="boxPanel" style="margin-bottom: 10px;" class="leftFloat"></div> <div class="leftFloat"> <div style="margin-bottom:10px"><input type="button" id="btnStart" value="开始" /> </div> <div><input type="button" id="btnPause" value="暂停" disabled = true /> </div> </div> </body> </html>
时间: 2024-11-10 13:34:45