俄罗斯方块

<!DOCTYPE html>
<!-- saved from url=(0066)http://xzh-loop.github.io/Manji/lab/html5game/20141114-tetris.html -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>C# 文档</title>
</head>
<body><canvas id="canvas" width="502" height="500" style="border:1px solid black;"></canvas>
<div style="display:inline-block;">
A: 左移<br>
D:右移<br>
S:下移<br>
Space:变换方向<br>
</div>
<script>

var i, j, tmp,
    score = 500,
    eachScore = 0,  //每块砖头值多少分
    winScore = 20*30, //胜利所需分数
    speed = 400,    //初始速度ms, the more little the more fast
    qia = 1,    //关卡
    qiaSpeed = 50, //每个关卡提升的速度
    qiaScore = winScore,   //每个关卡增加多少胜利分数(注意score每关会累积)
    nBrick = Math.floor(Math.random()*5), //下一个砖头的形状
    nIsOverturn = Math.floor(Math.random()*2),
    nDirection = Math.floor(Math.random()*4),
    BOARD = [],
    SHAPE = ['Tian','Chu','Tu','Thunder','Line'],
    canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    brickWidth = 20,    //砖块大小
    width = 400, height = 500;  //画布宽高,20X25

ctx.strokeStyle = 'black';  //砖块边框颜色

// 主界面网格显示,@dev
// for(i=0;i<20;i++) {
//     for(j=0;j<25;j++) {
//         ctx.strokeRect(brickWidth*i, brickWidth*j, brickWidth, brickWidth);   //注意+1和减2
//     }
// }

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() {
    ctx.fillStyle = 'rgb('+Math.floor(Math.random()*256)+','+Math.floor(Math.random()*256)+','+Math.floor(Math.random()*256)+')';
    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
    }
}
Brick.prototype.move = function(moveX, moveY) {
    //---终止判定---
    tmp = this.embattle[this.isOverturn][this.direction];
    var as = BOARD[this.originX+tmp[0]%4][this.originY+Math.floor(tmp[0]/4)+1],
        bs = BOARD[this.originX+tmp[1]%4][this.originY+Math.floor(tmp[1]/4)+1],
        cs = BOARD[this.originX+tmp[2]%4][this.originY+Math.floor(tmp[2]/4)+1],
        ds = BOARD[this.originX+tmp[3]%4][this.originY+Math.floor(tmp[3]/4)+1];
    // 横向移动违规
    if((this.originX==0 && moveX==-1) 
        || (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)) {
            return;
    }
    // 纵向终止
    if((as==1 || bs==1 || cs==1 || ds==1) && moveX==0) {
        clearInterval(this.autoMoveTimer);
        this.autoMoveTimer = null;
        BOARD[this.originX+tmp[0]%4][this.originY+Math.floor(tmp[0]/4)] = 1;
        BOARD[this.originX+tmp[1]%4][this.originY+Math.floor(tmp[1]/4)] = 1;
        BOARD[this.originX+tmp[2]%4][this.originY+Math.floor(tmp[2]/4)] = 1;
        BOARD[this.originX+tmp[3]%4][this.originY+Math.floor(tmp[3]/4)] = 1;
        
        // 全民爱消除~
        ALabel:for(i=0;i<4;i++) {
            var k = this.originY+Math.floor(tmp[i]/4);
            for(j=0;j<20;j++) {
                if(BOARD[j][k] == 0) {
                    continue ALabel;
                }
            }

            ctx.clearRect(410,0,100,100);
            ctx.save();
            ctx.fillStyle = 'black';
            score += 20*eachScore;  //加分
            ctx.fillText('分数:'+score,410,30);
            ctx.fillText('关卡:'+qia,410,50);
            ctx.fillText('胜利需:'+winScore,410,70);
            ctx.restore();

            for(j=k;j>0;j--) {
                for(var p=0;p<20;p++) {
                    BOARD[p][j] = BOARD[p][j-1];
                }
            }
            for(j=0;j<20;BOARD[j][0]=0,j++);    //初始化第一行
            for(var p=0;p<20;p++) {
                for(j=0;j<=k;j++) {
                    if(BOARD[p][j]==0) {
                        ctx.clearRect(p*brickWidth, j*brickWidth, brickWidth, brickWidth);
                    } else {
                        ctx.fillRect(p*brickWidth, j*brickWidth, brickWidth, brickWidth);
                        ctx.strokeRect(p*brickWidth+1, j*brickWidth+1, brickWidth-2, brickWidth-2);
                    }
                }
            } 
        }

        if(this.originY<0) {
            alert("You fail!!!");
            return;
        }
        while(score>=winScore) {
            alert('You win!!!');
            init();
            return;
        }

        deleteObj(b);   //为什么无法删除该对象?
        NextBrick();    //出现下一个
        return;
    }

    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 = function() {
    var status, self = this;
    this.autoMoveTimer = setInterval(function() {
        status = self.move(0,1);
    },speed);
}
Brick.prototype.change = function() {
    var ox = this.originX, oy = this.originY,
        originDirection = this.direction;
    this.direction = (this.direction+1)%4,
    tmp = this.embattle[this.isOverturn][this.direction];
    // 变换方向之后如果有部分溢出了右边界,将整体左移
    while(ox+tmp[0]%4 > 19 || ox+tmp[1]%4 > 19 || ox+tmp[2]%4 > 19 || ox+tmp[3]%4 > 19) {
        ox -= 1;
    }
    if(BOARD[ox+tmp[0]%4][oy+Math.floor(tmp[0]/4)] == 0
        && BOARD[ox+tmp[1]%4][oy+Math.floor(tmp[1]/4)] == 0
        && BOARD[ox+tmp[2]%4][oy+Math.floor(tmp[2]/4)] ==0
        && BOARD[ox+tmp[3]%4][oy+Math.floor(tmp[3]/4)] ==0) {
            // 清除原位置
            for(i=0;i<4;i++) {
                tmp = this.embattle[this.isOverturn][originDirection][i];
                ctx.clearRect((this.originX+tmp%4)*brickWidth, (this.originY+Math.floor(tmp/4))*brickWidth, brickWidth, brickWidth);
            }
            this.originX = ox;
            this.originY = oy;
            this.draw();
    } else {
        this.direction = originDirection;   //还原方向
    }
}
function Tian(isModel) {
    this.embattle = [
        [ [0,1,4,5], [0,1,4,5], [0,1,4,5], [0,1,4,5] ], //布局表为4X4表格,数字为砖头位置
        [ [0,1,4,5], [0,1,4,5], [0,1,4,5], [0,1,4,5] ]   //布局表为4X4表格,数字为砖头位置
    ];
    isModel || this.autoMove();
}
function Chu(isModel) {
    this.embattle = [
        [ [0,1,4,8], [0,4,5,6], [1,5,8,9], [0,1,2,6] ] ,  //布局表为4X4表格,数字为砖头位置
        [ [0,1,5,9], [0,1,2,4], [0,4,8,9], [2,4,5,6] ]   //次行为翻转的情况
    ];
    isModel || this.autoMove();
}
function Tu(isModel) {
    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] ]   //次行为翻转的情况
    ];
    isModel || this.autoMove();
}
function Thunder(isModel) {
    this.embattle = [
        [ [0,4,5,9], [1,2,4,5], [0,4,5,9], [1,2,4,5] ],  //布局表为4X4表格,数字为砖头位置
        [ [1,4,5,8], [0,1,5,6], [1,4,5,8], [0,1,5,6] ]   //次行为翻转的情况
    ];
    isModel || this.autoMove();
}
function Line(isModel) {
    this.embattle = [
        [ [0,4,8,12], [0,1,2,3], [0,4,8,12], [0,1,2,3] ],  //布局表为4X4表格,数字为砖头位置
        [ [0,4,8,12], [0,1,2,3], [0,4,8,12], [0,1,2,3] ]   //布局表为4X4表格,数字为砖头位置
    ];
    isModel || this.autoMove();
}
// 继承父类
Tian.prototype = new Brick();
Tian.prototype.constructor = Tian;
Chu.prototype = new Brick();
Chu.prototype.constructor = Chu;
Tu.prototype = new Brick();
Tu.prototype.constructor = Tu;
Thunder.prototype = new Brick();
Thunder.prototype.constructor = Thunder;
Line.prototype = new Brick();
Line.prototype.constructor = Line;

//--------------------------------------
init(1);
function init(isFirstInit) {
    if(!isFirstInit) {
        speed -= qia*qiaSpeed;
        qia += 1;
        winScore += qiaScore;
    }
    ctx.clearRect(0,0,500,500);
    // 初始化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;
            }
        }
    }

    // 初始界面的一些内容,如主界面与信息界面的分割线、分数、关卡
    ctx.save();
    ctx.moveTo(401,0);
    ctx.strokeStyle = 'red';
    ctx.lineWidth = '1';
    ctx.lineTo(401,500);
    ctx.stroke();
    ctx.fillStyle = 'black';
    ctx.fillText('分数:'+score,410,30);
    ctx.fillText('关卡:'+qia,410,50);
    ctx.fillText('胜利需:'+winScore,410,70);
    ctx.restore();

    NextBrick();
}

window.document.onkeydown = function(evt) {    //事件处理是否也应该放进对象里?
    evt = (evt) ? evt : window.event;
    // console.log(evt.keyCode)
    switch(evt.keyCode){
        case 65: b.move(-1,0); break;   //还区分大小写?
        case 97: b.move(-1,0); break;
        case 68: b.move(1,0); break;
        case 100: b.move(1,0); break;
        case 83: b.move(0,1); break;
        case 115: b.move(0,1); break;
        case 32: b.change(); break;
    }
}

function NextBrick() {
    b = new window[SHAPE[nBrick]]();
    b.direction = nDirection;
    b.isOverturn = nIsOverturn;

    nBrick = Math.floor(Math.random()*5);   //下一个的形状
    nDirection = Math.floor(Math.random()*4);   //下一个的方向
    nIsOverturn = Math.floor(Math.random()*2);  //下一个的翻转

    ctx.clearRect(410,100,100,100);
    ctx.strokeRect(410,100,80,80);
    var show = new window[SHAPE[nBrick]](1);
    var em = show.embattle[nIsOverturn][nDirection];
    for(var u=0;u<4;u++) {
        ctx.fillRect(410+em[u]%4*10,100+Math.floor(em[u]/4)*10,10,10);
        ctx.strokeRect(410+em[u]%4*10+1,100+Math.floor(em[u]/4)*10+1,10-2,10-2)
    }
    // deleteObj(this, show);   //这里无须手动回收
}

// 这里提供彻底清除对象的方法
function deleteObj(obj) {
    // console.log(obj);
    if(typeof(obj)==='object') {
        for(var e in obj) {
            // console.log(e);
            if(typeof(e)==='object' && obj.hasOwnProperty(e)) {
                deleteObj(obj[e]);
            } else {
                // console.log(Object.getOwnPropertyDescriptor(obj, e));
                delete obj[e];
            }
        }
    }
    delete obj;
    // console.log(obj);
}
</script></body></html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值