一直纠结要不要发上来,对js不熟悉,对HTML5也只是知道个名称而已,css就更不会了。感觉有点班门弄斧的味道,让各位大虾,大牛们见笑了。之所以要做这个游戏,源于自己一直想做游戏软件,之所以采用js是因为方便,不用安装什么编译器,用editplus直接写,用浏览器运行就OK了(不喜欢太复杂的东东)。代码一次发不完,只好分开发了,正好重新回顾一下,这些天每天都写一点,写着写着就写完了........
(PS:没有做过浏览器兼容测试,我自己是在chrome上运行的,同事说ff也可以)。    最开始,我是看到网上说canvas标签是能做动画,我本来想做一个网页3D的东东,但是资料显示canvas目前就只能做2D的,虽然也搜索到了老外做的3D的例子,但都是伪3D的,而且设计到算法也是很复杂,就放弃了。然后买了一本书,看看用canvas能搞些啥,看了几天也就是画一些基本图形,其中我最喜欢画矩形了,因为简单啊。画圆的话书里面讲的是什么贝塞尔曲线,彻底蒙鸟。然后画着画着,就想把他做成一个类,于是乎,这个游戏的第一个类Rect就诞生了,当然最初没有这么多东西,都是后面慢慢加上去的。    再然后,我就用了for循环去画一些小矩形做颜色渐变的练习,当画满整个canvas标签时,我发现这个有点像地图了,那一个个小矩形就想地图上的坐标一样。发现这一点很兴奋,立刻想到了贪吃蛇游戏(那个游戏只实现了基本功能,连计分功能都没有,不算完整就不发了),于是地图类map就这样被设计出来了,在写俄罗斯方块的时候又增加了刷新refresh功能。    接着就开始着手俄罗斯方块类的设计,这个花了几天时间因为那几天在看软件设计模式中的简单工厂模式,考虑到扩展性,如果多加几种俄罗斯方块,代码怎么设计才改动最少。最终得出的结论是用继承,也就是说把左移,右移,旋转等公用方法写在父类里面,多增加一种方块的话我只需要增加一个类定义出它的形状就可以了。    另一个花时间比较多的是旋转的算法,网上大致有两种算法,一种是用数组画出所有选择后的图形,直接调用,一种是根据坐标旋转。前者简单,但是麻烦。后者的算法我没看懂。最后通过将各种俄罗斯方块(出了“田”和竖条)都画到一个3 * 3的地图里,我打算利用矩阵旋转的方法来实现,还是因为简单啊,呵呵。公式是这样的:a[j][2 - i] = a[i][j] 就能把一个二维矩阵旋转一下,而俄罗斯方块由四个Rect组成,每个Rect的x,y就相当于i,j了,x = y; y = 2 - x 就行了,而且把第一个Rect定义为中心的话,只需要计算出另外3个Rect的坐标即可。但是在实际测试中,却失败了,旋转后各个Rect就飞了。原来,矩阵里面的i,j都是从0,0开始的,而我的俄罗斯方块随着下降左移右移,坐标早就不知道偏移到哪去了,这个使我郁闷了很久,不过后来一想,先按照矩阵旋转的算法算完之后,再加上偏移量就可以了哇。通过中心的那个Rect的坐标计算出偏移量也是很方便的。最后写完代码发现,核心代码也就10来行。不过竖条不在3*3范围内,但是我那个算法也能把竖条旋转了,这个是我没想到的,感觉很意外。        //用于画地图的方块类
        function Rect(x,y,size,context) {
            this.x = x;
            this.y = y;
            this.size = size;
            //是否着色的标志,由游戏控制类来改写
            this.issetcolor = false;
            this.color = "";
            this.context = context;
        }
        //画边框,用于画地图
        Rect.prototype.strokerect = function (sColor) {
            this.context.strokeStyle = sColor;
            this.context.strokeRect(this.x * this.size,this.y * this.size,this.size,this.size);
        }
        //填充颜色
        Rect.prototype.fillrect = function (sColor) {
            this.context.fillStyle = sColor;
            this.context.fillRect(this.x * this.size + 1,this.y * this.size + 1,this.size - 2, this.size - 2);
            this.color = sColor;
        }
        //清除颜色
        Rect.prototype.clearrect = function () {
            this.context.clearRect(this.x * this.size + 1,this.y * this.size + 1,this.size - 2,this.size - 2);
        }  
        //地图类
        function map(RectSize,color,canvas) {
            this.width = canvas.width;
            this.height = canvas.height;
            this.RectSize = RectSize; //方块边长
            this.backgroundcolor = color;
            this.aMapArray = null;
            this.ctx = canvas.getContext("2d");
            this.born();
        }
        //地图由若干只有边框的方块组成
        map.prototype.born = function () {
            var i; var j;
            var xCount;
            var yCount;
            xCount = this.width / this.RectSize;
            yCount = this.height / this.RectSize;
            this.aMapArray = new Array();
            for (i = 0; i < xCount; i++) {
                this.aMapArray[i] = new Array();
                for (j = 0; j < yCount; j++) {
                    this.aMapArray[i][j] = new Rect(i,j,this.RectSize,this.ctx);
                    this.aMapArray[i][j].strokerect(this.backgroundcolor);
                    this.aMapArray[i][j].fillrect(this.backgroundcolor);
                }
            }
        }
        //地图刷新
        map.prototype.refresh = function () {
            var xCount;
            var yCount;
            xCount = this.width / this.RectSize;
            yCount = this.height / this.RectSize;
            for (var i = 0; i < xCount; i++) {
                for (var j = 0; j < yCount; j++) {
                    this.aMapArray[i][j].fillrect("White");
                    this.aMapArray[i][j].fillrect(this.backgroundcolor);
                    this.aMapArray[i][j].issetcolor = false;
                }
            }
        }
        //获取地图上的方块
        map.prototype.getrect = function (x,y) {
            try {
                return this.aMapArray[x][y];
            }
            catch (err) {
                return null;
            }
        }
        //俄罗斯方块父类 
        function tetris(x,y,size,scolor) {
            //出生坐标  
            this.born_x = x;
            this.born_y = y;
            //方块边长
            this.rectsize = size;
            //存放方块的数组
            this.rectarray = new Array();
            //方块的颜色
            this.color = scolor;
            //方块名称
            this.name = "";
            //属于哪个地图
            this.map = map;
        }
        tetris.prototype.setbornxy = function (x,y) {
            this.born_x = x;
            this.born_y = y;
        }
        //显示方块
        tetris.prototype.show = function () {
            var iCount = this.rectarray.length;
            for (var i = 0; i < iCount; i++) {
                this.rectarray[i].fillrect(this.color);
            }
        }
        //清除方块
        tetris.prototype.clear = function () {
            var iCount = this.rectarray.length;
            for (var i = 0; i < iCount; i++) {
                //this.rectarray[i].clearrect();
                this.rectarray[i].fillrect("Black");
            }
        }
        //方块的旋转
        tetris.prototype.trun = function () {
            var iCount = this.rectarray.length;
            var iTemp_x, iTemp_y, offset_x, offset_y;
            /*
            以rectarray的第一个方块为中心,
            在定义方块时,需要将这个方块设置为中心
            由于是按照中心方块来移动,所以中心方块坐标不用变。
            */
            if (this.name != "D") {//我实在是找不出哪个字母比D更像“田”了
                this.clear();
                //取得方块所在矩阵偏移原点(0,0)的偏移量
                offset_x = this.rectarray[0].x - 1;
                offset_y = this.rectarray[0].y - 1;
                for (var i = 1; i < iCount; i++) {
                    //方块坐标减去偏移量
                    iTemp_x = this.rectarray[i].x - offset_x;
                    iTemp_y = this.rectarray[i].y - offset_y;
                    /*
                    以原点坐标做矩阵旋转运算 参考公式 array[j][2 - i] = array[i][j]
                    逆时针旋转
                    计算完后,再加上偏移量
                    */
                    this.rectarray[i].x = iTemp_y + offset_x;
                    this.rectarray[i].y = 2 - iTemp_x + offset_y;
                }
                this.show();
            }
        }
        //方块左移
        tetris.prototype.move_left = function () {
            /*
            左移就是x坐标减1
            */
            var iCount = this.rectarray.length;
            this.clear();
            for (var i = 0; i < iCount; i++) {
                this.rectarray[i].x = this.rectarray[i].x - 1;
            }
            this.show();
        }
        //方块右移
        tetris.prototype.move_right = function (context) {
            /*
            右移就是x坐标加1
            */
            var iCount = this.rectarray.length;
            this.clear();
            for (var i = 0; i < iCount; i++) {
                this.rectarray[i].x = this.rectarray[i].x + 1;
            }
            this.show();
        }
        //方块下移
        tetris.prototype.move_down = function (context) {
            /*
            下移就是y坐标加1
            */
            var iCount = this.rectarray.length;
            this.clear();
            for (var i = 0; i < iCount; i++) {
                this.rectarray[i].y = this.rectarray[i].y + 1;
            }
            this.show();
        }

解决方案 »

  1.   

    父类设计完后,接下来就是7种俄罗斯方块,this.rectarray[0]为中心Rect,其余3个Rect的可按照任意顺序定义位置。        /*
            所有方块继承自俄罗斯方块父类
            ps:学习Javascript的继承 :)
            */
            function tetris_T(x, y, size, scolor) {
                tetris.call(this, x, y, size, scolor); //构造方法的继承
            }
            tetris_T.prototype = new tetris(); //属性和函数的继承
            tetris_T.prototype.born = function (context) {
                this.rectarray[0] = new Rect(this.born_x, this.born_y, this.rectsize, context); //中心方块
                this.rectarray[1] = new Rect(this.born_x + 1, this.born_y, this.rectsize, context);
                this.rectarray[2] = new Rect(this.born_x, this.born_y - 1, this.rectsize, context);
                this.rectarray[3] = new Rect(this.born_x - 1, this.born_y, this.rectsize, context);
                this.name = "T";
            }        function tetris_1(x, y, size, scolor, map) {
                tetris.call(this, x, y, size, scolor, map); //构造方法的继承
            }
            tetris_1.prototype = new tetris(); //属性和函数的继承
            tetris_1.prototype.born = function (context) {
                this.rectarray[0] = new Rect(this.born_x, this.born_y, this.rectsize, context);
                this.rectarray[1] = new Rect(this.born_x - 1, this.born_y, this.rectsize, context);
                this.rectarray[2] = new Rect(this.born_x + 1, this.born_y, this.rectsize, context);
                this.rectarray[3] = new Rect(this.born_x + 2, this.born_y, this.rectsize, context);
                this.name = "1";
            }        function tetris_D(x, y, size, scolor, map) {
                tetris.call(this, x, y, size, scolor, map); //构造方法的继承
            }
            tetris_D.prototype = new tetris(); //属性和函数的继承
            tetris_D.prototype.born = function (context) {
                this.rectarray[0] = new Rect(this.born_x, this.born_y, this.rectsize, context);
                this.rectarray[1] = new Rect(this.born_x + 1, this.born_y, this.rectsize, context);
                this.rectarray[2] = new Rect(this.born_x + 1, this.born_y - 1, this.rectsize, context);
                this.rectarray[3] = new Rect(this.born_x, this.born_y - 1, this.rectsize, context);
                this.name = "D";
            }
            function tetris_LL(x, y, size, scolor, map) {
                tetris.call(this, x, y, size, scolor, map); //构造方法的继承
            }
            tetris_LL.prototype = new tetris(); //属性和函数的继承
            tetris_LL.prototype.born = function (context) {
                this.rectarray[0] = new Rect(this.born_x, this.born_y, this.rectsize, context);
                this.rectarray[1] = new Rect(this.born_x + 1, this.born_y, this.rectsize, context);
                this.rectarray[2] = new Rect(this.born_x - 1, this.born_y - 1, this.rectsize, context);
                this.rectarray[3] = new Rect(this.born_x - 1, this.born_y, this.rectsize, context);
                this.name = "LL";
            }
            function tetris_RL(x, y, size, scolor, map) {
                tetris.call(this, x, y, size, scolor, map); //构造方法的继承
            }
            tetris_RL.prototype = new tetris(); //属性和函数的继承
            tetris_RL.prototype.born = function (context) {
                this.rectarray[0] = new Rect(this.born_x, this.born_y, this.rectsize, context);
                this.rectarray[1] = new Rect(this.born_x + 1, this.born_y, this.rectsize, context);
                this.rectarray[2] = new Rect(this.born_x + 1, this.born_y - 1, this.rectsize, context);
                this.rectarray[3] = new Rect(this.born_x - 1, this.born_y, this.rectsize, context);
                this.name = "RL";
            }
            function tetris_RZ(x, y, size, scolor, map) {
                tetris.call(this, x, y, size, scolor, map); //构造方法的继承
            }
            tetris_RZ.prototype = new tetris(); //属性和函数的继承
            tetris_RZ.prototype.born = function (context) {
                this.rectarray[0] = new Rect(this.born_x, this.born_y, this.rectsize, context);
                this.rectarray[1] = new Rect(this.born_x + 1, this.born_y - 1, this.rectsize, context);
                this.rectarray[2] = new Rect(this.born_x, this.born_y - 1, this.rectsize, context);
                this.rectarray[3] = new Rect(this.born_x - 1, this.born_y, this.rectsize, context);
                this.name = "RZ";
            }
            function tetris_Z(x, y, size, scolor, map) {
                tetris.call(this, x, y, size, scolor, map); //构造方法的继承
            }
            tetris_Z.prototype = new tetris(); //属性和函数的继承
            tetris_Z.prototype.born = function (context) {
                this.rectarray[0] = new Rect(this.born_x, this.born_y, this.rectsize, context);
                this.rectarray[1] = new Rect(this.born_x + 1, this.born_y, this.rectsize, context);
                this.rectarray[2] = new Rect(this.born_x, this.born_y - 1, this.rectsize, context);
                this.rectarray[3] = new Rect(this.born_x - 1, this.born_y - 1, this.rectsize, context);
                this.name = "Z";
            }
      

  2.   

    产生俄罗斯方块的工厂        //方块工厂类 用于产生不同形状的方块
            function rectfactory(rectsize) {
                this.rectsize = rectsize;
                this.colorarray = new Array("red", "green", "blue", "orange", "purple", "pink", "yellow");
            }
            //产生方块
            rectfactory.prototype.createfactory = function (x, y, witch, icolor) {
                var tetris;
                switch (witch) {
                    case 0:
                        tetris = new tetris_T(x, y, this.rectsize, this.colorarray[icolor]);
                        break;
                    case 1:
                        tetris = new tetris_1(x, y, this.rectsize, this.colorarray[icolor]);
                        break;
                    case 2:
                        tetris = new tetris_D(x, y, this.rectsize, this.colorarray[icolor]);
                        break;
                    case 3:
                        tetris = new tetris_LL(x, y, this.rectsize, this.colorarray[icolor]);
                        break;
                    case 4:
                        tetris = new tetris_RL(x, y, this.rectsize, this.colorarray[icolor]);
                        break;
                    case 5:
                        tetris = new tetris_RZ(x, y, this.rectsize, this.colorarray[icolor]);
                        break;
                    case 6:
                        tetris = new tetris_Z(x, y, this.rectsize, this.colorarray[icolor]);
                        break;
                    default:
                        tetris = null;
                }
                return tetris;
            }
      

  3.   

    游戏控制类,一次还发不完。其中判断方块能否左移,右移,下移,旋转的方法写的不好,是把俄罗斯方块父类中计算Rect坐标的代码拷贝过来再做判断,代码复用性不好。//游戏控制类
            function tetrisgame(canvas,canvas2) {
                this.rectsize = 20;
                this.map = new map(this.rectsize, "Black", canvas);
                //预览下一个俄罗斯方块的地图
                this.map2 = new map(this.rectsize, "Black", canvas2);
                this.tetrisfactory = new rectfactory(this.rectsize);
                this.tetris = null; //当前俄罗斯方块
                this.tetris2 = null; //下一个俄罗斯方块
                this.rectcreate_x = parseInt(this.map.aMapArray.length / 2);
    this.score = 0;
    this.scorebord = document.getElementById("score");
    this.level = 0;//级别(随分数变化而增加)
    this.isstart = false;
            };
    //判断是否Game Over 方块不能再向下移动时调用
            tetrisgame.prototype.isgameover = function (tetris) {
                var iCount = tetris.rectarray.length;
                var bHas = false;
                //有方块的y坐标小于0时,这个俄罗斯方块就算挂了
                for (var i = 0; i < iCount; i++) {
                    if (tetris.rectarray[i].y < 0) {
                        bHas = true;
                        break;
                    }
                }
                return bHas;
            }
            //游戏结束后把一些属性初始化
            tetrisgame.prototype.gameover = function () {
                this.stop();
                this.tetris = null;
                this.tetris2 = null;
    this.score = 0;
                alert("Game Over!");
                this.map.refresh();
                this.map2.refresh();
            };
            //产生俄罗斯方块
            tetrisgame.prototype.createrect = function () {
                var icolor, ikind;
                icolor = parseInt(Math.random() * (this.tetrisfactory.colorarray.length - 1));
                ikind = parseInt(Math.random() * 6);
                //return this.tetrisfactory.createfactory(this.rectcreate_x,-1,ikind,icolor);
                return this.tetrisfactory.createfactory(2, 2, ikind, icolor);
            }
            //判断方块能否再继续向下移动
            tetrisgame.prototype.iscanmove_down = function (tetris, map) {
                var iCount = tetris.rectarray.length;
                var bord_y = map.aMapArray[0].length;
                var result = true;
                var x, y, maprect;
                for (var i = 0; i < iCount; i++) {
                    x = tetris.rectarray[i].x;
                    y = tetris.rectarray[i].y + 1;
                    maprect = map.getrect(x, y);
                    if (maprect == null && y < 0) {//方块刚产生时有些坐标超出了边界,这时不应该报错
                        continue;
                    }
                    else if (maprect == null && y >= bord_y) {//这个判断是用于刚产生方块时,就移出边界了
                        result = false;
                        break;
                    }
                    else if (maprect.issetcolor || y >= bord_y) {//超出边界和地图上的方块有着色了都不能移
                        result = false;
                        break;
                    }
                }
                return result;
            }
            //判断方块能否再继续向左移动
            tetrisgame.prototype.iscanmove_left = function (tetris, map) {
                var iCount = tetris.rectarray.length;
                var result = true;
                var x, y, maprect;
                for (var i = 0; i < iCount; i++) {
                    x = tetris.rectarray[i].x - 1;
                    y = tetris.rectarray[i].y;
                    maprect = map.getrect(x, y);
                    if (maprect == null && x >= 0) {//方块刚产生时有些坐标超出了边界,这时不应该报错
                        continue;
                    }
                    else if (x < 0 || maprect.issetcolor) {//超出边界,地图方块着色都不能移
                        result = false;
                        break;
                    }
                }
                return result;
            }
            //判断方块能否再继续向右移动
            tetrisgame.prototype.iscanmove_right = function (tetris, map) {
                var iCount = tetris.rectarray.length;
                var bord_x = map.aMapArray.length;
                var bord_y = map.aMapArray[0].length;
                var result = true;
                var x, y, maprect;
                for (var i = 0; i < iCount; i++) {
                    x = tetris.rectarray[i].x + 1;
                    y = tetris.rectarray[i].y;
                    maprect = map.getrect(x, y);
                    if (maprect == null && x < bord_x) {//判断逻辑同左移
                        continue;
                    }
                    else if (x >= bord_x || maprect.issetcolor) {
                        result = false;
                        break;
                    }
                }
                return result;
            }
            //判断方块能否旋转
            tetrisgame.prototype.iscanturn = function (tetris, map) {
                var iCount = tetris.rectarray.length;
                var bord_x = map.aMapArray.length;
                var bord_y = map.aMapArray[0].length;
                var x, y, iTemp_x, iTemp_y, offset_x, offset_y;
                var result = true;
                var rect = null;
                if (tetris.name != "D") {
                    offset_x = tetris.rectarray[0].x - 1;
                    offset_y = tetris.rectarray[0].y - 1;
                    for (var i = 1; i < iCount; i++) {
                        iTemp_x = tetris.rectarray[i].x - offset_x;
                        iTemp_y = tetris.rectarray[i].y - offset_y;
                        x = iTemp_y + offset_x;
                        y = 2 - iTemp_x + offset_y;
                        if (x < 0 || x >= bord_x || y >= bord_y) {//超出边界
                            result = false;
                            break;
                        }
                        else if (y < 0) {//方块刚产生时存在坐标小于0的情况
                            continue;
                        }
                        else {//着色的地方不能再旋转了
                            rect = map.getrect(x, y);
                            if (rect == null || rect.issetcolor) {
                                result = false;
                                break;
                            }
                        }
                    }
                }
                return result;
            }
            //方块落下后对方块所在坐标的地图方块标记已着色
            tetrisgame.prototype.setmapcolor = function (tetris, map) {
                var iCount = tetris.rectarray.length;
                var x, y;
                for (var i = 0; i < iCount; i++) {
                    x = tetris.rectarray[i].x;
                    y = tetris.rectarray[i].y;
                    map.aMapArray[x][y].issetcolor = true;
                    map.aMapArray[x][y].color = tetris.color;
                }
            }
            //方块落下记录需要消除的层,然后消层,降落
            tetrisgame.prototype.clearup = function (tetris, map) {
                var iCount = tetris.rectarray.length;
                var xCount = map.aMapArray.length;
                var yCount = 0;
                var bAll = false; //整行是否都着色了
                var bHas = false; //是否有着色的
                var cleararray = new Array();
                //获取俄罗斯方块中方块的最大y坐标
                for (var i = 0; i < iCount; i++) {
                    if (yCount < tetris.rectarray[i].y) {
                        yCount = tetris.rectarray[i].y;
                    }
                }
                //计算哪些层需要消除
                for (var j = yCount; j >= 0; j--) {
                    bAll = true;
                    bHas = false;
                    for (var i = 0; i < xCount; i++) {
                        if (map.aMapArray[i][j].issetcolor) {
                            bHas = true;
                        }
                        else {
                            bAll = false;
                        }
                    }
                    //整行都是,则记录起来
                    if (bAll) {
                        cleararray[cleararray.length] = j;
                    }
                    //整行都没有则break
                    if (!bHas) {
                        break;
                    }
                }
                //消层;
                this.doclearup(cleararray);
                //降落
                this.falldown(cleararray);
            }
            //消层
            tetrisgame.prototype.doclearup = function (cleararray) {
                var iCount = cleararray.length;
                var xCount = this.map.aMapArray.length;
                var score = 0;
    var yTemp;
                if (iCount > 0) {//根据记录中要消除的层数,将那一层填充为地图背景色
                    for (var j = 0; j < iCount; j++) {
                        yTemp = cleararray[j];
                        for (var i = 0; i < xCount; i++) {
                            this.map.aMapArray[i][yTemp].fillrect(this.map.backgroundcolor);
                            this.map.aMapArray[i][yTemp].issetcolor = false;
                        }
                    }
    //消层后计算分数
                    score = this.calcscore(cleararray);
    this.setscore(score);
                }
            }
      

  4.   

    感谢楼上,我又可以继续发了。
    关于消层后降落:由于消除的层数都记录在数组里面,而且都是从大到小的顺序,就从最小那一层把上面的方块降落的这层,一次类推。start()中设置动画 和 键盘监听事件 是从网上找的。        //降落
            tetrisgame.prototype.falldown = function (cleararray) {
                var iCount = cleararray.length;
                var xCount = this.map.aMapArray.length;
                var yPre, yNow, color, bHasColor;
                /*
                1、cleararray记录的是消除的层数,下标最大的为最上面消除的层数
                2、从最上面消除的层数循环降落,直至最下面消除的层数
                3、降落其实就是将消除的那一层(y)着色为上一层(y - 1)的颜色
                然后再向上降落,直至上层都没有了颜色则停止
                */
                if (iCount > 0) {
                    for (var j = iCount - 1; j >= 0; j--) {//倒循环cleararray
                        bHasColor = true;
                        yNow = cleararray[j];
                        while (yNow > 0 && bHasColor) {//消除的那一层一次向上做降落动作,直到上一层没有着色的方块或者到顶了
                            bHasColor = false;
                            yPre = yNow - 1;
                            for (var i = 0; i < xCount; i++) {
                                color = this.map.aMapArray[i][yPre].color; //获取上一层的方块颜色
                                this.map.aMapArray[i][yNow].fillrect(color); //本层着色(颜色为上一层的颜色)
                                if (color != "Black") {
                                    bHasColor = true;
                                    this.map.aMapArray[i][yNow].issetcolor = true;
                                }
                                else {
                                    this.map.aMapArray[i][yNow].issetcolor = false;
                                }
                            }
                            yNow = yNow - 1;
                        }
                    }
                }
            }
    //设置分数
    tetrisgame.prototype.setscore = function(score){
      var temp;
      this.score = this.score + score;
      if (this.level < 9){
        temp = this.score / 20;//20分一个等级
       this.level = temp.toFixed(0);
      }
              this.scorebord.innerHTML = "得分: " + this.score;
    }
    //计算得分 得分公式 2 * (n - 1) + 1 n 为连续消除了n层
    tetrisgame.prototype.calcscore = function(cleararray){
      var iCount = cleararray.length;
      var result,result1;
      //获取所有层数的和
      function sum(cleararray){
        var sum = 0;
    for (var i = 0; i < iCount ;i++ ){
          sum = sum + cleararray[i];
    }
    return sum;
      }
      switch (iCount){
        case 1 : 
      return 1;//消除1层得1分
      break;
    case 2 : 
      result = cleararray[0] - cleararray[1]; 
      if (result == 1){//连续2层得3分
        return 3;
      }
      else {
        return 2;//不连续就得2分
      }
      break;
                case 3 :
      result = 3 * (cleararray[0] + cleararray[2]) / 2; 
      result1 = sum(cleararray);
      if (result == result1){
        return 7;//连续3层是7分
      }
      else{
        /*
    如果消除了3层,不是连续的话,
    只可能是连续的2层 和不连续的1层,
    得分都是 3 + 1 = 4
    */
    return 4;
      }
      break; 
                case 4 ://如果消除了4层只可能是连续的4层
       return 15; 
       break; 
        default :
     return 0;
      }
    }
            //直接调用 setTimeOut(this.start())不行,貌似是因为循环的时候this对象丢失
            //以下是网上查到的办法
            tetrisgame.prototype.delay = function (obj, fn, time) {
                fnGameDelay = function () {
                    fn.call(obj); // call方法会把fn方法中的this关键字替换成obj对象  
                };
                return setTimeout('fnGameDelay()', time);
            };
            //暂停
            tetrisgame.prototype.stop = function () {
                clearTimeout(this.timeOut);
            };
            //游戏开始
            tetrisgame.prototype.start = function () {
                var icolor, ikind, x, cleararray,level;
                if (this.tetris == null && this.tetris2 == null) {
                    this.tetris = this.createrect();
                    this.tetris.setbornxy(this.rectcreate_x, -1);
                    this.tetris.born(this.map.ctx); //方块出生在哪个地图
                    this.tetris.show();
                    this.tetris2 = this.createrect();
                    this.tetris2.born(this.map2.ctx);
                    this.tetris2.show();
                }
                if (this.tetris == null) {
                    this.tetris = this.tetris2;
                    this.tetris.setbornxy(this.rectcreate_x, -1);
                    this.tetris.born(this.map.ctx);                this.tetris2 = this.createrect();
                    this.tetris2.born(this.map2.ctx);
                    this.map2.refresh();
                    this.tetris2.show();
                }
                if (this.iscanmove_down(this.tetris, this.map)) {
                    this.tetris.move_down();
                }
                else {
                    //是否gameover
                    if (this.isgameover(this.tetris)) {
                        this.gameover();
                    }
                    this.setmapcolor(this.tetris, this.map);
                    //消层
                    this.clearup(this.tetris, this.map);
                    this.tetris = null;
                }
                //设置动画
    level = 1000 - this.level * 100;
                this.timeOut = this.delay(this, this.start, level);
            };        // 键盘监听事件  
            tetrisgame.prototype.keyboardEventsListeners = function (oEvent) {
                if (window.event) {// ie   
                    var direc = window.event.keyCode;
                } else if (oEvent.which) {// ff  
                    var direc = oEvent.which;
                }
                if (direc == 37 || direc == 65) {// 37-->left 65 --> A  
                    if (this.iscanmove_left(this.tetris, this.map)) {
                        this.tetris.move_left();
                    }
                }
                else if (direc == 39 || direc == 68) {// 39-->right  68 --> D
                    if (this.iscanmove_right(this.tetris, this.map)) {
                        this.tetris.move_right();
                    }
                }
                else if (direc == 38 || direc == 87) {// 38-->up  87--> W
                    if (this.iscanturn(this.tetris, this.map)) {
                        this.tetris.trun();
                    }
                }
                else if (direc == 40 || direc == 83) {// 40-->down  83 --> S
                    /*
                    if (this.iscanmove_down(this.tetris,this.map)){
                    this.tetris.move_down();
                    }
                    */
                    this.stop();
                    this.start();
                }
                else {
                    return;
                }
            };
      

  5.   

    最后是程序入口函数        var canvas;
            var ctx;
            function init() {
                //获取canvas
                canvas = document.getElementById("canvas");
                ctx = canvas.getContext("2d");            canvas2 = document.getElementById("canvas2");
                ctx2 = canvas2.getContext("2d");
                var TetrisGame = new tetrisgame(canvas,canvas2);
                //键盘事件和按钮事件
                document.body.onkeydown = function (oEvent) {
                    TetrisGame.keyboardEventsListeners.call(TetrisGame, oEvent);
                }
                document.getElementById("BtnStart").onclick = function () {
                    TetrisGame.start.call(TetrisGame);
                }
                document.getElementById("BtnStop").onclick = function () {
                    TetrisGame.stop.call(TetrisGame);
                }
            }以下是Html的代码,有html5的标签又有html的标签,感觉不太好,css还是请bigwatercar帮我弄的,我实在不会,简单排版一下。<!doctype html>
    <html>
    <head>
        <meta charset="gbk" />
        <style type="text/css">
            body
            {
                border: 0;
                text-align: center;
            }
            #container
            {
                margin: 0 auto;
                width: 800px;
            }
            #leftside, #top, #ctrl
            {
                float: left;
                margin-left: 20px;
            }
    #score
    {
      font-size:20px;
      font-style:normal;
      color:"red";
      text-align: center; }
        </style>
    </head>
    <body onload="init()">
        <div id="container">
            <div id="leftside">
                <canvas id="canvas" width="260" height="500" style="border: solid 15px #000; background-color: #FFF;">
                    <p>
                        该吃药了,亲!浏览器不支持canvas元素,建议使用最新版chrome,firefox等浏览器,ie就别用了</p>
                </canvas>
            </div>
            <div id="top">
                <canvas id="canvas2" width="100" height="100" style="border: solid 5px #000; background-color: #FFF;">
                </canvas>
    <br/>
    <span id="score">
      
    </span>
            </div>
        </div>
        <div id="ctrl">
            <input id="BtnStart" class="" type="button" value="点我开始" />
            <input id="BtnStop" class="" type="button" value="点我暂停" />
        </div>
    </body>
    </html>
      

  6.   

    我元旦节也写了一个,
    http://yaowt.webng.com/game.htm
      

  7.   

    厉害a ~~~~我是菜鸟刚刚学习JS
      

  8.   

    算上html代码大概700多行,注释也蛮多的,记录了一些当时的思路,怕以后看不懂.
    我做这个不是赶流行,初学js还没有那么强的能力用100多行就能写出来.
    只是学了这么久的编程,一直想自己写个完整的小游戏.
    2是把学习到的设计模式和js练习一下.
    平时工作不是用js的,都是闲时看看资料,做做练习,不知道能不能坚持下去```