标签:
废话都就不多说了,直接贴代码
<!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>
标签:
原文地址:http://my.oschina.net/u/2011113/blog/504840