javascript俄罗斯方块【附带源码】

在看了W3C的关于ECMScript的对象及继承后,先是完成贪吃蛇的实现。最近又抽空实现了下俄罗斯方块。对于俄罗斯方块重要的不是游戏本身,而是在这个过程中对于javascript继承的使用。

当然在一些对象的划分及使用过程还存在瑕疵,算法也不算最优,发布出源码只是想做个交流。以下就提供源代码供大家参考,也为自己做个备份。也可在直接点击下载。游戏效果图为:

这里对代码不做说明了,可以看代码块中的注释

[javascript] view plain copy print ?
  1. //********************************Utils.js*******************************************************   
  2. /**  
  3.  * 辅助类  
  4.  * @author leeyee  
  5.  * @blog blog.csdn.net/oxcow  
  6.  * @email seadlead@gmail.com  
  7.  * @data 2010-4  
  8.  */  
  9. /** 
  10.  * 创建DOM元素 
  11.  *  
  12.  * @param sTagName 
  13.  *            元素名 
  14.  * @param sTagId 
  15.  *            元素ID 
  16.  * @param sText 
  17.  *            元素文本 
  18.  * @return DOM元素对象 
  19.  */  
  20. function createElement(sTagName, sTagId, sText) {  
  21.     var oElement = document.createElement(sTagName);  
  22.     if (sTagId != null) {  
  23.         oElement.setAttribute("id", sTagId);  
  24.     }  
  25.     if (sText != null) {  
  26.         oElement.appendChild(document.createTextNode(sText));  
  27.     }  
  28.     return oElement;  
  29. }  
  30. function RandomEventUtils() {  
  31. }  
  32. /** 
  33.  * 得到从零到N的随机整数 
  34.  *  
  35.  * @param iN 
  36.  *            最大整数 
  37.  * @return 0-iN的随机整数 
  38.  */  
  39. RandomEventUtils.getIntRandomNumFromZeroToN = function(iN) {  
  40.     var iR = Math.random() * iN;  
  41.     return Math.round(iR);// 舍尾取数   
  42. };  
  43. /** 
  44.  * 获取某个元素在数组中的位置 
  45.  *  
  46.  * @param vItem 
  47.  *            目标元素 
  48.  * @return 目标元素在数组中的索引 
  49.  */  
  50. Array.prototype.indexOf = function(vItem) {  
  51.     for ( var i = 0; i < this.length; i++) {  
  52.         if (vItem == this[i]) {  
  53.             return i;  
  54.         }  
  55.     }  
  56.     return -1;  
  57. };  
  58. /** 
  59.  * 获取数组的长度。不包括undefined元素 
  60.  *  
  61.  * @return 
  62.  */  
  63. Array.prototype._length = function() {  
  64.     var __len = 0;  
  65.     for ( var i = 0; i < this.length; i++) {  
  66.         if (this[i] != undefined) {  
  67.             __len++;  
  68.         }  
  69.     }  
  70.     return __len;  
  71. };  
  72. /** 
  73.  * 清除数组中的undefined元素 
  74.  *  
  75.  * @return 数组清除后的数组(数组长度改变) 
  76.  */  
  77. Array.prototype.cleanUndefinedElement = function() {  
  78.     for ( var i = 0; i < this.length; i++) {  
  79.         if (this[i] == undefined) {  
  80.             this.splice(i--, 1);  
  81.         }  
  82.     }  
  83.     return this;  
  84. };  
  85. /** 
  86.  * 创建一个长度为 iLen 的二维数组,其中第二位数组的长度未定义 
  87.  *  
  88.  * @param iLen 
  89.  *            数组长度 
  90.  * @return 
  91.  */  
  92. function createTwoDimensionArray(iLen) {  
  93.     var __aDefaultArray = new Array(iLen);  
  94.     for ( var i = 0; i < iLen; i++) {  
  95.         __aDefaultArray[i] = new Array();  
  96.     }  
  97.     return __aDefaultArray;  
  98. }  
  99. /** 
  100.  * 将目标数组 aObj 以 iN 分组。具有相同商的放在相同维度中,同时根据余数确定二维存放位置<br/> 
  101.  *  
  102.  * 比如将 [1,3,21] 以10分组,那么返回的二维数组为:[[1,,3],[],[21]] 
  103.  *  
  104.  * @param aObj 
  105.  *            目标数组 
  106.  * @param iN 
  107.  *            分组因子 
  108.  * @return 一个长度为20的二维数组 
  109.  */  
  110. function elementGroupByN(aObj, iN) {  
  111.     var __aZeroArray = createTwoDimensionArray(20, new Array());  
  112.     for ( var i = 0; i < aObj.length; i++) {  
  113.         var __quotient = Math.floor((aObj[i] - 1) / iN);// 取商(被10除,商相同的元素为一组)   
  114.         var __remainder = (aObj[i] - 1) % iN;// 取余   
  115.         __aZeroArray[__quotient][__remainder] = aObj[i];// 商相同的放在相同维度的余数位置   
  116.     }  
  117.     return __aZeroArray;  
  118. }  
  119. // ***********************************************Canvas.js*******************************************************   
  120.   
  121. /** 
  122.  * 俄罗斯方块所在画布类 
  123.  *  
  124.  * @author leeyee 
  125.  * @blog blog.csdn.net/oxcow 
  126.  * @email seadlead@gmail.com 
  127.  * @data 2010-4 
  128.  * @param iRow 
  129.  *            画布行数 
  130.  * @param iColumn 
  131.  *            画布列数 
  132.  * @param sOffset 
  133.  *            画布显示位置 
  134.  */  
  135. function Canvas(iRow, iColumn, sOffset) {  
  136.     this.row = iRow;// 行   
  137.     this.column = iColumn;// 列   
  138.     this.offset = sOffset;// 显示位置   
  139. }  
  140. Canvas.prototype.draw = function() {  
  141.     var oDiv_canvas = document.getElementById(this.offset);  
  142.     if (oDiv_canvas == null) {  
  143.         oDiv_canvas = createElement("div"this.offset, null);  
  144.         document.body.appendChild(oDiv_canvas);  
  145.     }  
  146.     var oFragment = document.createDocumentFragment();// 创建文档碎片   
  147.     for ( var i = 1; i <= this.row * this.column; i++) {  
  148.         var oSpan = createElement("span", i, null);  
  149.         oFragment.appendChild(oSpan);  
  150.     }  
  151.     oDiv_canvas.appendChild(oFragment);  
  152. };  
  153. /** 
  154.  * 预览画布类 
  155.  *  
  156.  * @param iRow 
  157.  *            行数 
  158.  * @param iColumn 
  159.  *            列数 
  160.  * @param sOffset 
  161.  *            显示位置 
  162.  * @return 
  163.  */  
  164. function PreCanvas(iRow, iColumn, sOffset) {  
  165.     this.row = iRow;  
  166.     this.column = iColumn;  
  167.     this.offset = sOffset;  
  168. }  
  169. PreCanvas.prototype.draw = function() {  
  170.     var oDiv_preCanvas = document.getElementById(this.offset);  
  171.     if (oDiv_preCanvas == null) {  
  172.         oDiv_preCanvas = createElement("div"this.offset, null);  
  173.         document.body.appendChild(oDiv_preCanvas);  
  174.     }  
  175.     var oFragment = document.createDocumentFragment();// 创建文档碎片   
  176.     for ( var i = -(this.row * this.column) + 11; i < 11; i++) {  
  177.         var oSpan = createElement("span""pre_" + i, null);  
  178.         oFragment.appendChild(oSpan);  
  179.     }  
  180.     oDiv_preCanvas.appendChild(oFragment);  
  181. };  
  182. PreCanvas.prototype.show = function(oArray) {  
  183.     for ( var i = -(this.row * this.column) + 11; i < 11; i++) {  
  184.         var __oE = document.getElementById("pre_" + i);  
  185.         if (__oE) {  
  186.             __oE.style.background = document.getElementById(this.offset).style.background;  
  187.         }  
  188.     }  
  189.     for ( var i = 0; i < oArray.length; i++) {  
  190.         var __oE = document.getElementById("pre_" + oArray[i]);  
  191.         if (__oE) {  
  192.             __oE.style.background = "blue";  
  193.         }  
  194.     }  
  195. };  
  196. // *************************************Tetris.js**********************************************************************   
  197. /** 
  198.  * 俄罗斯方块类 
  199.  *  
  200.  * @author leeyee 
  201.  * @blog blog.csdn.net/oxcow 
  202.  * @email seadlead@gmail.com 
  203.  * @data 2010-4 
  204.  */  
  205.   
  206. /** 
  207.  * 基础类 
  208.  *  
  209.  * @param iAxis 
  210.  *            旋转轴 
  211.  * @param aBodys 
  212.  *            方块体 
  213.  * @return 
  214.  */  
  215. function Tetris(iAxis, aBodys) {  
  216.     this.axis = iAxis;  
  217.     this.body = aBodys;  
  218. }  
  219. Tetris.column = 10;// 列数   
  220.   
  221. /** 
  222.  * Tetris 工厂 
  223.  *  
  224.  * @return 返回Tetris实例 
  225.  */  
  226. Tetris.Factory = function() {  
  227.     var __oTetris = null;  
  228.     var __iAxis = -15;// 默认轴   
  229.     var __iAngle = RandomEventUtils.getIntRandomNumFromZeroToN(4) * 90;// 角度   
  230.     var __iType = RandomEventUtils.getIntRandomNumFromZeroToN(9);// 类型   
  231.     switch (__iType) {  
  232.     case 0:  
  233.     case 8:  
  234.         __oTetris = new I_Tetris(__iAxis, __iAngle);  
  235.         break;  
  236.     case 1:  
  237.         __oTetris = new O_Tetris(__iAxis);  
  238.         break;  
  239.     case 2:  
  240.     case 7:  
  241.         __oTetris = new S_Tetris(__iAxis, __iAngle);  
  242.         break;  
  243.     case 3:  
  244.         __oTetris = new L_Tetris(__iAxis, __iAngle);  
  245.         break;  
  246.     case 4:  
  247.         __oTetris = new Z_Tetris(__iAxis, __iAngle);  
  248.         break;  
  249.     case 5:  
  250.         __oTetris = new T_Tetris(__iAxis, __iAngle);  
  251.         break;  
  252.     case 6:  
  253.         __oTetris = new J_Tetris(__iAxis, __iAngle);  
  254.         break;  
  255.     default:  
  256.         __oTetris = new T_Tetris(__iAxis, __iAngle);  
  257.         break;  
  258.     }  
  259.     return __oTetris;  
  260. };  
  261. /** 
  262.  * 显示方块 
  263.  */  
  264. Tetris.prototype.draw = function() {  
  265.     for ( var i = 0; i < this.body.length; i++) {  
  266.         var _oE = document.getElementById(this.body[i]);  
  267.         if (_oE)  
  268.             _oE.style.background = "#135";  
  269.     }  
  270. };  
  271. /** 
  272.  * 擦除方块 
  273.  */  
  274. Tetris.prototype.eraser = function() {  
  275.     for ( var i = 0; i < this.body.length; i++) {  
  276.         var _oE = document.getElementById(this.body[i]);  
  277.         if (_oE) {  
  278.             _oE.style.background = document.getElementById("canvas").style.background;  
  279.         }  
  280.     }  
  281. };  
  282. /** 
  283.  * 旋转修正.避免旋转过后超出画布范围 
  284.  *  
  285.  * @return 
  286.  */  
  287. Tetris.prototype.rotateTune = function(aBody) {  
  288.     this.body = aBody;  
  289.     // 修正Tetris的转动轴axis及调整修正转动轴后的body   
  290.     if (this.axis % Tetris.column == 1) {  
  291.         for ( var i = 0; i < this.body.length; i++) {  
  292.             this.body[i]++;  
  293.         }  
  294.         this.axis++;  
  295.     }  
  296.     if (this.axis % Tetris.column == 0) {  
  297.         for ( var i = 0; i < this.body.length; i++) {  
  298.             this.body[i] -= 2;  
  299.         }  
  300.         this.axis -= 1;  
  301.     }  
  302. };  
  303. /** 
  304.  * 移动Tetris 
  305.  *  
  306.  * -1:左移动 +1:右移 +10:下移 
  307.  *  
  308.  * @param iOffset 
  309.  *            位移 
  310.  * @return 
  311.  */  
  312. Tetris.prototype.move = function(iOffset) {  
  313.     this.eraser();  
  314.     for ( var i = 0; i < this.body.length; i++) {  
  315.         this.body[i] += iOffset;  
  316.     }  
  317.     this.axis += iOffset;  
  318.     this.draw();  
  319. };  
  320. /** 
  321.  * O-型方块类.O-型方块旋转没有变化,因此无需调用基类rotate方法 
  322.  *  
  323.  * @param iAxis 
  324.  *            旋转轴 
  325.  * @return 
  326.  */  
  327. function O_Tetris(iAxis) {  
  328.     Tetris.call(this, iAxis, new Array(+iAxis - 1, +iAxis, +iAxis  
  329.             + Tetris.column - 1, +iAxis + Tetris.column));  
  330. }  
  331. // 为了使用父类的属性和方法,需要将子类的prototye属性设置成父类的实例,这样就实现了继承。下同   
  332. O_Tetris.prototype = new Tetris();  
  333. O_Tetris.prototype.rotate = function() {  
  334.     return;  
  335. };  
  336. /** 
  337.  * I-型方块类 
  338.  *  
  339.  * @param iAxis 
  340.  *            旋转轴 
  341.  * @param iAngle 
  342.  *            角度(枚举类型0/180/360,90/270).I型为0/180/360度 
  343.  * @return 
  344.  */  
  345. function I_Tetris(iAxis, iAngle) {  
  346.     Tetris.call(this, iAxis, I_Tetris.newITetrisBody(iAxis, iAngle));  
  347.     this.iAngle = iAngle;  
  348. }  
  349. /** 
  350.  * 创建新的I-型方块.I-型方块旋转只有两种变化.180或360度的都可看作为0度的 
  351.  *  
  352.  * @param iAxis 
  353.  *            旋转轴 
  354.  * @param iAngle 
  355.  *            角度 
  356.  * @return 
  357.  */  
  358. I_Tetris.newITetrisBody = function(iAxis, iAngle) {  
  359.     var __iBody = null;  
  360.     switch (iAngle) {  
  361.     case 0:  
  362.     case 180:  
  363.     case 360:  
  364.         iAxis = (iAxis % 10 == 0) ? iAxis -= 2 : (iAxis % 10 == 9) ? iAxis -= 1  
  365.                 : iAxis;  
  366.         __iBody = new Array(iAxis - 1, iAxis, iAxis + 1, iAxis + 2);  
  367.         break;  
  368.     case 90:  
  369.     case 270:  
  370.         __iBody = new Array(iAxis - Tetris.column, iAxis,  
  371.                 iAxis + Tetris.column, iAxis + 2 * Tetris.column);  
  372.         break;  
  373.     default:  
  374.         __iBody = new Array(iAxis - 1, iAxis, iAxis + 1, iAxis + 2);  
  375.         break;  
  376.     }  
  377.     return __iBody;  
  378. };  
  379. I_Tetris.prototype = new Tetris();  
  380. I_Tetris.prototype.rotate = function() {  
  381.     this.iAngle = (this.iAngle == 360) ? 90 : this.iAngle + 90;  
  382.     this.rotateTune(I_Tetris.newITetrisBody(this.axis, this.iAngle));  
  383. };  
  384. /** 
  385.  * L-型方块类 
  386.  *  
  387.  * @param iAxis 
  388.  *            旋转轴 
  389.  * @param iAngle 
  390.  *            角度(枚举类型0/360,90,180,270)L型为0度,每次顺时针旋转90度 
  391.  * @return 
  392.  */  
  393. function L_Tetris(iAxis, iAngle) {  
  394.     Tetris.call(this, iAxis, L_Tetris.newLTetrisBody(iAxis, iAngle));  
  395.     this.iAngle = iAngle;  
  396. }  
  397. /** 
  398.  * 创建新的L-型方块 
  399.  *  
  400.  * @param iAxis 
  401.  *            旋转轴 
  402.  * @param iAngle 
  403.  *            角度 
  404.  * @return 
  405.  */  
  406. L_Tetris.newLTetrisBody = function(iAxis, iAngle) {  
  407.     var __lBody = null;  
  408.     switch (iAngle) {  
  409.     case 0:  
  410.     case 360:  
  411.         __lBody = new Array(iAxis - Tetris.column, iAxis,  
  412.                 iAxis + Tetris.column, iAxis + Tetris.column + 1);  
  413.         break;  
  414.     case 90:  
  415.         __lBody = new Array(iAxis + 1, iAxis, iAxis - 1, iAxis + Tetris.column  
  416.                 - 1);  
  417.         break;  
  418.     case 180:  
  419.         __lBody = new Array(iAxis + Tetris.column, iAxis,  
  420.                 iAxis - Tetris.column, iAxis - Tetris.column - 1);  
  421.         break;  
  422.     case 270:  
  423.         __lBody = new Array(iAxis - 1, iAxis, iAxis + 1, iAxis - Tetris.column  
  424.                 + 1);  
  425.         break;  
  426.     default:  
  427.         __lBody = new Array(iAxis - Tetris.column, iAxis,  
  428.                 iAxis + Tetris.column, iAxis + Tetris.column + 1);  
  429.         break;  
  430.     }  
  431.     return __lBody;  
  432. };  
  433. L_Tetris.prototype = new Tetris();  
  434. L_Tetris.prototype.rotate = function() {  
  435.     this.iAngle = (this.iAngle == 360) ? 90 : this.iAngle + 90;  
  436.     this.rotateTune(L_Tetris.newLTetrisBody(this.axis, this.iAngle));  
  437. };  
  438. /** 
  439.  * J-型方块类 
  440.  *  
  441.  * @param iAxis 
  442.  *            旋转轴 
  443.  * @param iAngle 
  444.  *            角度(枚举类型0/360,90,180,270)J型为0度,每次顺时针旋转90度 
  445.  * @return 
  446.  */  
  447. function J_Tetris(iAxis, iAngle) {  
  448.     Tetris.call(this, iAxis, J_Tetris.newJTetrisBody(iAxis, iAngle));  
  449.     this.iAngle = iAngle;  
  450. }  
  451. /** 
  452.  * 创建新的J-型方块 
  453.  *  
  454.  * @param iAxis 
  455.  *            旋转轴 
  456.  * @param iAngle 
  457.  *            角度 
  458.  * @return 
  459.  */  
  460. J_Tetris.newJTetrisBody = function(iAxis, iAngle) {  
  461.     var __jBody = null;  
  462.     switch (iAngle) {  
  463.     case 0:  
  464.     case 360:  
  465.         __jBody = new Array(iAxis - Tetris.column, iAxis,  
  466.                 iAxis + Tetris.column, iAxis + Tetris.column - 1);  
  467.         break;  
  468.     case 90:  
  469.         __jBody = new Array(iAxis + 1, iAxis, iAxis - 1, iAxis - Tetris.column  
  470.                 - 1);  
  471.         break;  
  472.     case 180:  
  473.         __jBody = new Array(iAxis + Tetris.column, iAxis,  
  474.                 iAxis - Tetris.column, iAxis - Tetris.column + 1);  
  475.         break;  
  476.     case 270:  
  477.         __jBody = new Array(iAxis - 1, iAxis, iAxis + 1, iAxis + Tetris.column  
  478.                 + 1);  
  479.         break;  
  480.     default:  
  481.         __jBody = new Array(iAxis - Tetris.column, iAxis,  
  482.                 iAxis + Tetris.column, iAxis + Tetris.column - 1);  
  483.         break;  
  484.     }  
  485.     return __jBody;  
  486. };  
  487. J_Tetris.prototype = new Tetris();  
  488. J_Tetris.prototype.rotate = function() {  
  489.     this.iAngle = (this.iAngle == 360) ? 90 : this.iAngle + 90;  
  490.     this.rotateTune(J_Tetris.newJTetrisBody(this.axis, this.iAngle));  
  491. };  
  492. /** 
  493.  * T-型方块类 
  494.  *  
  495.  * @param iAxis 
  496.  *            旋转轴 
  497.  * @param iAngle 
  498.  *            角度(枚举类型0/360,90,180,270)T型为0度,每次顺时针旋转90度 
  499.  * @return 
  500.  */  
  501. function T_Tetris(iAxis, iAngle) {  
  502.     Tetris.call(this, iAxis, T_Tetris.newTTetrisBody(iAxis, iAngle));  
  503.     this.iAngle = iAngle;  
  504. }  
  505. /** 
  506.  * 创建新的T-型方块 
  507.  *  
  508.  * @param iAxis 
  509.  *            旋转轴 
  510.  * @param iAngle 
  511.  *            角度 
  512.  * @return 
  513.  */  
  514. T_Tetris.newTTetrisBody = function(iAxis, iAngle) {  
  515.     var __tBody = null;  
  516.     switch (iAngle) {  
  517.     case 0:  
  518.     case 360:  
  519.         __tBody = new Array(iAxis - 1, iAxis, iAxis + 1, iAxis + Tetris.column);  
  520.         break;  
  521.     case 90:  
  522.         __tBody = new Array(iAxis - Tetris.column, iAxis,  
  523.                 iAxis + Tetris.column, iAxis - 1);  
  524.         break;  
  525.     case 180:  
  526.         __tBody = new Array(iAxis + 1, iAxis, iAxis - 1, iAxis - Tetris.column);  
  527.         break;  
  528.     case 270:  
  529.         __tBody = new Array(iAxis + Tetris.column, iAxis,  
  530.                 iAxis - Tetris.column, iAxis + 1);  
  531.         break;  
  532.     default:  
  533.         __tBody = new Array(iAxis - 1, iAxis, iAxis + 1, iAxis + Tetris.column);  
  534.         break;  
  535.     }  
  536.     return __tBody;  
  537. };  
  538. T_Tetris.prototype = new Tetris();  
  539. T_Tetris.prototype.rotate = function() {  
  540.     this.iAngle = (this.iAngle == 360) ? 90 : this.iAngle + 90;  
  541.     this.rotateTune(T_Tetris.newTTetrisBody(this.axis, this.iAngle));  
  542. };  
  543. /** 
  544.  * S-型方块类 
  545.  *  
  546.  * @param iAxis 
  547.  *            旋转轴 
  548.  * @param iAngle 
  549.  *            角度(枚举类型0/180/360,90/270).S型为0/180/360度 
  550.  * @return 
  551.  */  
  552. function S_Tetris(iAxis, iAngle) {  
  553.     Tetris.call(this, iAxis, S_Tetris.newSTetrisBody(iAxis, iAngle));  
  554.     this.iAngle = iAngle;  
  555. }  
  556. /** 
  557.  * 创建新的S-型方块.S-型方块旋转只有两种变化.180或360度的都可看作为0度的 
  558.  *  
  559.  * @param iAxis 
  560.  *            旋转轴 
  561.  * @param iAngle 
  562.  *            角度 
  563.  * @return 
  564.  */  
  565. S_Tetris.newSTetrisBody = function(iAxis, iAngle) {  
  566.     var __sBody = null;  
  567.     switch (iAngle) {  
  568.     case 0:  
  569.     case 180:  
  570.     case 360:  
  571.         __sBody = new Array(iAxis + 1, iAxis, iAxis + Tetris.column, iAxis  
  572.                 + Tetris.column - 1);  
  573.         break;  
  574.     case 90:  
  575.     case 270:  
  576.         __sBody = new Array(iAxis - Tetris.column, iAxis, iAxis + 1, iAxis  
  577.                 + Tetris.column + 1);  
  578.         break;  
  579.     default:  
  580.         __sBody = new Array(iAxis + 1, iAxis, iAxis + Tetris.column, iAxis  
  581.                 + Tetris.column - 1);  
  582.         break;  
  583.     }  
  584.     return __sBody;  
  585. };  
  586. S_Tetris.prototype = new Tetris();  
  587. S_Tetris.prototype.rotate = function() {  
  588.     this.iAngle = (this.iAngle == 360) ? 90 : this.iAngle + 90;  
  589.     this.rotateTune(S_Tetris.newSTetrisBody(this.axis, this.iAngle));  
  590. };  
  591. /** 
  592.  * Z-型方块类 
  593.  *  
  594.  * @param iAxis 
  595.  *            旋转轴 
  596.  * @param iAngle 
  597.  *            角度(枚举类型0/180/360,90/270).Z型为0/180/360度 
  598.  * @return 
  599.  */  
  600. function Z_Tetris(iAxis, iAngle) {  
  601.     Tetris.call(this, iAxis, Z_Tetris.newZTetrisBody(iAxis, iAngle));  
  602.     this.iAngle = iAngle;  
  603. }  
  604. /** 
  605.  * 创建新的Z-型方块.Z-型方块旋转只有两种变化.180或360度的都可看作为0度的 
  606.  *  
  607.  * @param iAxis 
  608.  *            旋转轴 
  609.  * @param iAngle 
  610.  *            角度 
  611.  * @return 
  612.  */  
  613. Z_Tetris.newZTetrisBody = function(iAxis, iAngle) {  
  614.     var __zBody = null;  
  615.     switch (iAngle) {  
  616.     case 0:  
  617.     case 180:  
  618.     case 360:  
  619.         __zBody = new Array(iAxis - 1, iAxis, iAxis + Tetris.column, iAxis  
  620.                 + Tetris.column + 1);  
  621.         break;  
  622.     case 90:  
  623.     case 270:  
  624.         __zBody = new Array(iAxis - Tetris.column, iAxis, iAxis - 1, iAxis  
  625.                 + Tetris.column - 1);  
  626.         break;  
  627.     default:  
  628.         __zBody = new Array(iAxis - 1, iAxis, iAxis + Tetris.column, iAxis  
  629.                 + Tetris.column + 1);  
  630.         break;  
  631.     }  
  632.     return __zBody;  
  633. };  
  634. Z_Tetris.prototype = new Tetris();  
  635. Z_Tetris.prototype.rotate = function() {  
  636.     this.iAngle = (this.iAngle == 360) ? 90 : this.iAngle + 90;  
  637.     this.rotateTune(Z_Tetris.newZTetrisBody(this.axis, this.iAngle));  
  638. };  
  639.   
  640. // ******************************************TetrisGame.js***************************************************   
  641. /** 
  642.  * 俄罗斯方块游戏类 
  643.  *  
  644.  * @author leeyee 
  645.  * @blog blog.csdn.net/oxcow 
  646.  * @email seadlead@gmail.com 
  647.  * @data 2010-4 
  648.  */  
  649.   
  650. /** 
  651.  * 俄罗斯方块游戏类 
  652.  */  
  653. function TetrisGame() {  
  654.     this.timeOut;  
  655.     this.score = 0;// 得分   
  656.     this.level = 0;// 等级   
  657.     this.speed = 1000;// 降落速度   
  658.     this.canvas = new Canvas(20, 10, "canvas");// 创建canvas对象   
  659.     this.preCanvas = new PreCanvas(10, 4, "preCanvas");  
  660.     this.tetris = null;// 方块   
  661.     this.preTetris = Tetris.Factory();  
  662.     this.body = new Array();// 记录游戏中已经被占的格子   
  663. }  
  664. /** 
  665.  * 预计加载 
  666.  *  
  667.  * @return 
  668.  */  
  669. TetrisGame.prototype.preload = function() {  
  670.     this.displayScoreAndLevel();  
  671.     this.canvas["draw"]();  
  672.     this.preCanvas["draw"]();  
  673.     this.preCanvas["show"](this.preTetris.body);  
  674. };  
  675. /** 
  676.  * 创建新的方块 
  677.  *  
  678.  * @return 
  679.  */  
  680. TetrisGame.prototype.newTetris = function() {  
  681.     this.tetris = this.preTetris;  
  682.     this.preTetris = Tetris.Factory();  
  683.     this.preCanvas["show"](this.preTetris.body);  
  684. };  
  685. /** 
  686.  * 清除已经填满的行 
  687.  *  
  688.  * @author leeyee 
  689.  * @return 返回每次清除的行数 
  690.  */  
  691. TetrisGame.prototype.__eraserRow = function() {  
  692.     var __iRow = 0;// 清除的行数   
  693.     // 当数组长度超过80时,sort()方法无法正确排序,因此需要提供比较器   
  694.     // 关于比较器可参看http://www.w3school.com.cn/js/jsref_sort.asp   
  695.     this.body.sort(function(a, b) {  
  696.         return a - b;  
  697.     });  
  698.     // 将属于一行的元素放在相同的数组中,并通过二维数组的第一维确认其所在行   
  699.     var f = elementGroupByN(this.body, 10);  
  700.     var __temp = new Array();// 用于存储被销毁行上层的所占格子   
  701.     for ( var i = 0; i < f.length; i++) {  
  702.         if (f[i]["_length"]() == 0) {// 如果该行数组的长度(不统计未定义的数组元素)为0则说明该行尚未被占   
  703.             continue;  
  704.         }  
  705.         if (f[i]["_length"]() != 10) {// 如果该行有数据但未达到满格则记录下来   
  706.             __temp = __temp.concat(f[i]);  
  707.         } else if (f[i]["_length"]() == 10) {  
  708.             // 从已经占有的格子中清除属于一行的格子   
  709.             this.body.splice(this.body.indexOf(i * 10 + 1), 10);  
  710.             // 将需要清除的一行元素赋值给方块对象,并调用方块的eraser方法将其从画布上清除掉   
  711.             this.tetris.body = f[i];  
  712.             this.tetris["eraser"]();  
  713.             // 将被消除层的上层格子下移   
  714.             if (__temp.length != 0) {  
  715.                 this.tetris.body = __temp["cleanUndefinedElement"]();// 清除掉数组中未定义的元素   
  716.                 this.body.splice(0, this.tetris.body.length);// 从已占格子中清除上层各式   
  717.                 this.tetris["move"](10);// 上层格子下移   
  718.                 this.body = this.tetris.body.concat(this.body);// 将移动后的上层格子添加到已占格子的前端   
  719.             }  
  720.             __iRow++;  
  721.         }  
  722.     }  
  723.     return __iRow;  
  724. };  
  725. /** 
  726.  * 触碰事件 
  727.  *  
  728.  * @return 
  729.  */  
  730. TetrisGame.prototype.touchHandler = function() {  
  731.     this.tetris.body.sort();  
  732.     // 是否碰到已经被占的格子   
  733.     for ( var i = 0; i < 4; i++) {  
  734.         // 游戏结束   
  735.         if ((this.tetris.body[0] < 0 || Math.floor((this.tetris.body[i]) / 10) == 1)  
  736.                 && this.body.indexOf(this.tetris.body[i] + 10) != -1) {  
  737.             alert("GAME OVER");  
  738.             location.reload();  
  739.         }  
  740.         // 方块的组成中只要一个放块的下一个位置属于已经被占的就表明该方块不可以在往下移动了   
  741.         if (this.body.indexOf(this.tetris.body[i] + 10) != -1) {  
  742.             this.body = this.body.concat(this.tetris.body);  
  743.             this.scoreAndLevelHandler(this.__eraserRow());  
  744.             return true;  
  745.         }  
  746.     }  
  747.     // 表示方块的最后一个数是否属于最低层,属于就判断为已经到底   
  748.     if (Math.floor((this.tetris.body[3] - 1) / 10) == 19) {  
  749.         this.body = this.body.concat(this.tetris.body);  
  750.         this.scoreAndLevelHandler(this.__eraserRow());// 清除已经填满的行   
  751.         return true;  
  752.     }  
  753.     return false;  
  754. };  
  755. TetrisGame.prototype.rotateHandler = function() {  
  756.     var __tetrisBody = this.tetris.body;// 记录下变型前的方块对象的身体及角度   
  757.     var __tetrisAngle = this.tetris.iAngle;  
  758.     this.tetris.eraser();// 先清除方块对象   
  759.     this.tetris.rotate();  
  760.     for ( var i = 0; i < this.tetris.body.length; i++) {  
  761.         if (this.body.indexOf(this.tetris.body[i]) != -1) {// 假如变型后的位置已经有方块则返回变型前   
  762.             this.tetris.iAngle = __tetrisAngle;  
  763.             this.tetris.body = __tetrisBody;  
  764.             break;  
  765.         }  
  766.     }  
  767.     this.tetris.draw();// 展示方块对象   
  768. };  
  769. TetrisGame.prototype.scoreAndLevelHandler = function(iRow) {  
  770.     this.score += 10;// 每降落一个方块+10分   
  771.     if (iRow != 0) {// 消除一行100分;两行200分;三行400分;四行800分   
  772.         this.score += Math.pow(2, iRow - 1) * 100;  
  773.     }  
  774.     this.level = Math.floor(this.score / 400);  
  775.     if (this.speed > 130) {  
  776.         this.speed = 1000 - Math.floor(this.level / 3) * 80;  
  777.     }  
  778.     this.displayScoreAndLevel();  
  779. };  
  780. // 显示得分及等级   
  781. TetrisGame.prototype.displayScoreAndLevel = function() {  
  782.     document.getElementById("score").innerHTML = this.score;  
  783.     document.getElementById("level").innerHTML = this.level;  
  784. };  
  785. /** 
  786.  * 检测是否到达画布边缘.左或右 
  787.  *  
  788.  * @param sDirc 
  789.  *            left or right 
  790.  * @return 到达返回true.否则返回false 
  791.  */  
  792. TetrisGame.prototype.leftOrRightMove = function(sDirc) {  
  793.     for ( var i = 0; i < 4; i++) {  
  794.         // 判断是否已经到达最左边   
  795.         if (sDirc == "left") {  
  796.             if (this.tetris.body[i] % 10 == 1  
  797.                     && (this.tetris.body[i] - 1) % 10 == 0) {  
  798.                 return true;  
  799.             }  
  800.             if (this.body.indexOf(this.tetris.body[i] - 1) != -1) {  
  801.                 return true;  
  802.             }  
  803.         } else if (sDirc == "right") {  
  804.             // 判断是否已经到达最右边   
  805.             if (this.tetris.body[i] % 10 == 0  
  806.                     && (this.tetris.body[i] + 1) % 10 == 1) {  
  807.                 return true;  
  808.             }  
  809.             if (this.body.indexOf(this.tetris.body[i] + 1) != -1) {  
  810.                 return true;  
  811.             }  
  812.         } else {  
  813.             break;  
  814.         }  
  815.     }  
  816.     return false;  
  817. };  
  818. TetrisGame.prototype.keyboardEventsListeners = function(oEvent) {  
  819.     if (window.event) {// ie   
  820.         var direc = window.event.keyCode;  
  821.     } else if (oEvent.which) {// ff   
  822.         var direc = oEvent.which;  
  823.     }  
  824.     if (direc == 37) {// 37-->left   
  825.         if (!this.leftOrRightMove("left"))  
  826.             this.tetris.move(-1);  
  827.     }  
  828.     if (direc == 39) {// 39-->right   
  829.         if (!this.leftOrRightMove("right"))  
  830.             this.tetris.move(+1);  
  831.     }  
  832.     if (direc == 38) {// 38-->up   
  833.         this.rotateHandler();// 旋转   
  834.     }  
  835.     if (direc == 40) {// 40-->down   
  836.         if (this.touchHandler()) {  
  837.             this.newTetris();  
  838.         }  
  839.         this.tetris.move(+10);  
  840.     }  
  841. };  
  842. TetrisGame.prototype.__delay = function(obj, fn, time) {  
  843.     fnGameDelay = function() {  
  844.         // call方法会把fn方法中的this关键字替换成obj对象   
  845.         fn.call(obj);  
  846.         // apply方法同call,但参数要用数组形式。   
  847.         // IE中参数为空时不能用apply(obj,null),但FF中是可以的   
  848.         // fn.apply(obj, new Array());   
  849.     };  
  850.     return setTimeout("fnGameDelay()", time);  
  851. };  
  852. /** 
  853.  * 开始游戏 
  854.  *  
  855.  * @return 
  856.  */  
  857. TetrisGame.prototype.start = function() {  
  858.     if (this.tetris == null || this.touchHandler()) {  
  859.         this.newTetris();  
  860.     }  
  861.     this.tetris["move"](10);  
  862.     this.timeOut = this["__delay"](thisthis.start, this.speed);  
  863. };  
  864. /** 
  865.  * 暂停游戏 
  866.  *  
  867.  * @return 
  868.  */  
  869. TetrisGame.prototype.stop = function() {  
  870.     clearTimeout(this.timeOut);  
  871. };  
  872. // 重新开始   
  873. TetrisGame.prototype.restart = function() {  
  874.     location.reload();  
  875. };  
  876. window.onload = function() {  
  877.     var oTetrisGame = new TetrisGame();  
  878.     oTetrisGame["preload"]();  
  879.     document.onkeydown = function(oEvent) {  
  880.         oTetrisGame["keyboardEventsListeners"].call(oTetrisGame, oEvent);  
  881.     };  
  882.     document.getElementById("start").onclick = function() {  
  883.         oTetrisGame["start"].call(oTetrisGame);  
  884.     };  
  885.     document.getElementById("stop").onclick = function() {  
  886.         oTetrisGame["stop"].call(oTetrisGame);  
  887.     };  
  888.     document.getElementById("restart").onclick = function() {  
  889.         oTetrisGame["restart"].call(oTetrisGame);  
  890.     };  
  891. };  
tetris.html代码为
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  2. <html>  
  3. <head>  
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  5. <title>俄罗斯方块v1.0</title>  
  6. <mce:script type="text/javascript" src="Tetris1.0.js" mce_src="Tetris1.0.js"></mce:script>  
  7. <link type="text/css" rel="stylesheet" href="tetris.css" mce_href="tetris.css">  
  8. </head>  
  9. <body>  
  10. <div id="TetrisGame">  
  11. <div id="canvas"></div>  
  12. <div id="preCanvas"></div>  
  13. <div id="control"><label>分数:</label><span id="score"></span><br />  
  14. <label>等级:</label> <span id="level"></span> <br />  
  15. <button id="start">start</button>  
  16. <br />  
  17. <button id="stop">stop</button>  
  18. <br />  
  19. <button id="restart">restart</button>  
  20. </div>  
  21. <textarea rows="2" cols="40" id="debug" style="display: none" mce_style="display: none">  

这样就完成了一个简易的俄罗斯方块。如果觉得其中在一些对象的使用上不是很正确,可以说出来大家讨论讨论。

文章转自:http://blog.csdn.net/oxcow/article/details/5502650

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值