HTML5 實現(xiàn)的一個俄羅斯方塊實例代碼
示例簡單,運行地址為:http://chendd.cn/demo/html/canvas/elsfk.html,得需要支持html5瀏覽器的環(huán)境。
實現(xiàn)的功能:方塊旋轉(zhuǎn)(W鍵)、自動下落、移動(ASD)、消行、快速下落(空格鍵)、下落陰影、游戲結(jié)束。
為實現(xiàn)功能:消行時的計分、等級、以及不同等級的下落速度等。
學(xué)習(xí)了xiaoE的Java版本的俄羅斯方塊后,自己動手使用html5的canvas實現(xiàn)的,
參考效果圖如下:
詳細(xì)代碼如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>俄羅斯方塊</title> <style type="text/css"> /*整個畫布*/ #tetris { border: 6px solid grey; } /*游戲面板*/ </style> </head> <body> <canvas id="tetris" width="565" height="576"></canvas> <script type="text/javascript"> var canvas = document.getElementById("tetris"); var context = canvas.getContext("2d"); var padding = 6, size = 32, minX = 0, maxX = 10, minY = 0, maxY = 18, score = 0, level = 1; var gameMap = new Array(); //游戲地圖,二維數(shù)組 var gameTimer; initGameMap(); //繪制垂直線條 drawGrid(); var arrays = basicBlockType(); var blockIndex = getRandomIndex(); //隨機畫一個方塊意思意思 var block = getPointByCode(blockIndex); context.fillStyle = getBlockColorByIndex(blockIndex); drawBlock(block); /** * 初始化游戲地圖 */ function initGameMap() { for (var i = 0; i < maxY; i++) { var row = new Array(); for (var j = 0; j < maxX; j++) { row[j] = false; } gameMap[i] = row; } } /** * 方塊旋轉(zhuǎn) * 順時針: * A.x =O.y + O.x - B.y * A.y =O.y - O.x + B.x */ function round() { //正方形的方塊不響應(yīng)旋轉(zhuǎn) if (blockIndex == 4) { return; } //循環(huán)處理當(dāng)前的方塊,找新的旋轉(zhuǎn)點 for (var i = 1; i < block.length; i++) { var o = block[0]; var point = block[i]; //旋轉(zhuǎn)后的位置不能與現(xiàn)有格子的方塊沖突 var tempX = o.y + o.x - point.y; var tempY = o.y - o.x + point.x; if (isOverZone(tempX, tempY)) { return; //不可旋轉(zhuǎn) } } clearBlock(); //可以旋轉(zhuǎn),設(shè)置新的旋轉(zhuǎn)后的坐標(biāo) for (var i = 1; i < block.length; i++) { var o = block[0]; var point = block[i]; //旋轉(zhuǎn)后的位置不能與現(xiàn)有格子的方塊沖突 var tempX = o.y + o.x - point.y; var tempY = o.y - o.x + point.x; block[i] = { x: tempX, y: tempY }; } drawBlock(); } function moveDown() { var overFlag = canOver(); if(overFlag){ //如果不能向下移動了,將當(dāng)前的方塊坐標(biāo)載入地圖 window.clearInterval(gameTimer); add2GameMap(); //清除游戲區(qū)域內(nèi)的不同顏色的格子,使用單一顏色重新繪制地圖堆積物 redrawGameMap(); return;//游戲結(jié)束 } var flag = moveTo(0, 1); //如果可以移動,則繼續(xù)移動 if (flag) { return; } //如果不能向下移動了,將當(dāng)前的方塊坐標(biāo)載入地圖 add2GameMap(); //進(jìn)行消行動作 clearLines(); //清除游戲區(qū)域內(nèi)的不同顏色的格子,使用單一顏色重新繪制地圖堆積物 redrawGameMap(); //如果不能向下移動,則繼續(xù)下一個方塊 nextBlock(); } /** * 消行動作,返回消除的行數(shù) */ function clearLines() { var clearRowList = new Array(); for (var i = 0; i < maxY; i++) { var flag = true; for (var j = 0; j < maxX; j++) { if (gameMap[i][j] == false) { flag = false; break; } } if (flag) { clearRowList.push(i); //記錄消除行號的索引 } } var clearRows = clearRowList.length; //所謂的消行就是將待消除行的索引,下方所有的格子上移動 for (var x = 0; x < clearRows; x++) { var index = clearRowList[x]; for (var i = index; i > 0; i--) { for (var j = 0; j < maxX; j++) { gameMap[i][j] = gameMap[i - 1][j]; } } } if (clearRows > 0) { for (var i = 0; i < maxY; i++) { //此處可以限制滿足相關(guān)條件的方塊進(jìn)行清除操作&& j < clearRowList[clearRows - 1] for (var j = 0; j < maxX; j++) { if (gameMap[i][j] == false) { clearBlockByPoint(i, j); } } } } } /** * 重繪游戲地圖 */ function redrawGameMap() { drawGrid(); for (var i = 0; i < maxY; i++) { for (var j = 0; j < maxX; j++) { if (gameMap[i][j]) { roadBlock(j, i); } } } } /** * 打印陰影地圖 */ function drawShadowBlock() { var currentBlock = block; var shadowPoints = getCanMoveDown(); if (shadowPoints != null && shadowPoints.length > 0) { for (var i = 0; i < shadowPoints.length; i++) { var point = shadowPoints[i]; if (point == null) { continue; } var start = point.x * size; var end = point.y * size; context.fillStyle = "#abcdef"; context.fillRect(start, end, size, size); context.strokeStyle = "black"; context.strokeRect(start, end, size, size); } } } /** * 返回最多可移動到的坐標(biāo)位置(統(tǒng)計總共可以下落多少步驟) * @return最多可移動到的坐標(biāo)位置 */ function getCanMoveDown() { var nps = canMove(0, 1, block); var last = null; if (nps != null) { last = new Array(); while ((nps = canMove(0, 1, nps)) != null) { if (nps != null) { last = nps; } } } return last; } function canOver(){ var flag = false; for (var i = 0; i < block.length; i++) { var point = block[i]; var x = point.x; var y = point.y; if(isOverZone(x , y)){ flag = true; break; } } return flag; } function drawLevelScore() { } /** * 將不能移動的各種填充至地圖 */ function add2GameMap() { for (var i = 0; i < block.length; i++) { var point = block[i]; var x = point.x; var y = point.y; var gameMapRow = gameMap[y]; //獲取到地圖的一行 gameMapRow[x] = true; //將此行中的某個格子標(biāo)記為堆積物 gameMap[y] = gameMapRow; //再將行給設(shè)置回來 } } function moveLeft() { moveTo(-1, 0); } function moveRight() { moveTo(1, 0); } function quickDown() { while (moveTo(0, 1)); } function moveTo(moveX, moveY) { var move = canMove(moveX, moveY, block); //判定是否可以移動 if (move == null) { return false; } clearBlock(); for (var i = 0; i < block.length; i++) { var point = block[i]; point.x = point.x + moveX; point.y = point.y + moveY; } drawBlock(); return true; } /** * 下一個方塊 */ function nextBlock() { blockIndex = getRandomIndex(); block = getPointByCode(blockIndex); context.fillStyle = getBlockColorByIndex(blockIndex); drawBlock(); } document.onkeypress = function(evt) { var key = window.event ? evt.keyCode : evt.which; switch (key) { case 119: //向上旋轉(zhuǎn) W round(); break; case 115: //向下移動 S moveDown(); break; case 97: //向左移動 A moveLeft(); break; case 100: //向右移動 D moveRight(); break; case 32: //空格鍵快速下落到底 quickDown(); break; } } /** * 判定是否可以移動 * @parammoveX 橫向移動的個數(shù) * @parammoveY 縱向移動的個數(shù) */ function canMove(moveX, moveY, currentBlock) { var flag = true; var newPoints = new Array(); for (var i = 0; i < currentBlock.length; i++) { var point = currentBlock[i]; var tempX = point.x + moveX; var tempY = point.y + moveY; if (isOverZone(tempX, tempY)) { flag = false; break; } } if (flag) { for (var i = 0; i < currentBlock.length; i++) { var point = currentBlock[i]; var tempX = point.x + moveX; var tempY = point.y + moveY; newPoints[i] = { x: tempX, y: tempY }; } return newPoints; } return null; } /** * 判定是否可以移動 * @paramx 預(yù)移動后的橫坐標(biāo) * @paramy 預(yù)移動后的縱坐標(biāo) */ function isOverZone(x, y) { return x < minX || x >= maxX || y < minY || y >= maxY || gameMap[y][x]; } document.body.click(); gameTimer = window.setInterval(moveDown , 800); /** * 初始化方塊的基礎(chǔ)數(shù)據(jù) */ function basicBlockType() { var arrays = new Array(); arrays[0] = [{ x: 4, y: 0 }, { x: 3, y: 0 }, { x: 5, y: 0 }, { x: 6, y: 0 }]; arrays[1] = [{ x: 4, y: 0 }, { x: 3, y: 0 }, { x: 5, y: 0 }, { x: 4, y: 1 }]; arrays[2] = [{ x: 4, y: 0 }, { x: 3, y: 0 }, { x: 5, y: 0 }, { x: 3, y: 1 }]; arrays[3] = [{ x: 4, y: 0 }, { x: 5, y: 0 }, { x: 3, y: 1 }, { x: 4, y: 1 }]; arrays[4] = [{ x: 4, y: 0 }, { x: 5, y: 0 }, { x: 4, y: 1 }, { x: 5, y: 1 }]; arrays[5] = [{ x: 4, y: 0 }, { x: 3, y: 0 }, { x: 5, y: 0 }, { x: 5, y: 1 }]; arrays[6] = [{ x: 4, y: 0 }, { x: 3, y: 0 }, { x: 4, y: 1 }, { x: 5, y: 1 }]; return arrays; } function basicBlockColor() { return ["#A00000", "#A05000", "#A0A000", "#00A000", "#00A0A0", "#0000A0", "#A000A0"]; } function getBlockColorByIndex(typeCodeIndex) { var arrays = basicBlockColor(); return arrays[typeCodeIndex]; } /** * 根據(jù)編號返回指定編號的方塊 * @paramtypeCodeIndex 方塊編號索引 */ function getPointByCode(typeCodeIndex) { var arrays = basicBlockType(); return arrays[typeCodeIndex]; } /** * 獲取隨即出現(xiàn)方塊的范圍值 * @paramlens 隨機數(shù)的范圍 */ function getRandomIndex() { return parseInt(Math.random() * (arrays.length - 1), 10); } /** * 繪制方塊,按格子單個繪制 */ function drawBlock() { drawGrid(); for (var i = 0; i < block.length; i++) { var point = block[i]; var start = point.x * size; var end = point.y * size; context.fillStyle = getBlockColorByIndex(blockIndex); context.fillRect(start, end, size, size); context.strokeStyle = "black"; context.strokeRect(start, end, size, size); } drawShadowBlock(); } /** * 繪制障礙物 */ function roadBlock(x, y) { context.fillStyle = "darkgray"; var start = x * size; var end = y * size; context.fillRect(start, end, size, size); } /** * 繪制新的方塊先清除之前的方塊 */ function clearBlock() { for (var i = 0; i < block.length; i++) { var point = block[i]; var start = point.x * size; var end = point.y * size; context.clearRect(start, end, size, size); } } /** * 初始化一個新的行 */ function initGameMapRow() { var array = new Array(); for (var i = 0; i < maxX; i++) { array[i] = false; } return array; } /** * 根據(jù)坐標(biāo)清除指定格子的內(nèi)容 * @paramx 橫坐標(biāo) * @paramy 縱坐標(biāo) */ function clearBlockByPoint(x, y) { var start = y * size; var end = x * size; context.clearRect(start, end, size, size); } /** * 清掉所有位置的空白格的繪圖 */ function clearAllNullPoint() { for (var i = 0; i < maxY; i++) { for (var j = 0; j < maxX; j++) { if (gameMap[i][j] == false) { clearBlockByPoint(i, j); } } } } /** * 繪制網(wǎng)格線 * @paramcontext 繪圖對象 */ function drawGrid() { clearAllNullPoint(); //清除掉當(dāng)前方塊下落位置造成的陰影 context.strokeStyle = "grey"; //畫筆顏色 for (var i = 0; i <= maxX; i++) { var start = i * size; var end = start + size; context.beginPath(); context.moveTo(start, 0); context.lineTo(size * i, size * maxY); context.stroke(); context.closePath(); } //繪制水平線條 for (var i = 0; i <= maxY; i++) { var start = i * size; var end = start + size; context.beginPath(); context.moveTo(0, size * i); context.lineTo(size * maxX, size * i); context.stroke(); context.closePath(); } } </script> </body> </html>
以上就是HTML5 實現(xiàn)的一個俄羅斯方塊的實例,有興趣的小伙伴可以參考下,謝謝大家對本站的支持!
- 關(guān)于Android HTML5 audio autoplay無效問題的解決方案
- HTML5 canvas 9繪制圖片實例詳解
- js HTML5多圖片上傳及預(yù)覽實例解析(不含前端的文件分割)
- 手機端 HTML5使用photoswipe.js仿微信朋友圈圖片放大效果
- 使用HTML5+Boostrap打造簡單的音樂播放器
- 正則表達(dá)式與HTML5新元素
- NodeJS與HTML5相結(jié)合實現(xiàn)拖拽多個文件上傳到服務(wù)器的實現(xiàn)方法
- JS+HTML5手機開發(fā)之滾動和慣性緩動實現(xiàn)方法分析
- HTML5 移動頁面自適應(yīng)手機屏幕寬度詳解
相關(guān)文章
JS+CSS+HTML實現(xiàn)“代碼雨”類似黑客帝國文字下落效果
這篇文章主要介紹了JS+CSS+HTML實現(xiàn)“代碼雨”類似黑客帝國文字下落效果,需要的朋友可以參考下2020-03-03HTML+JS實現(xiàn)“代碼雨”效果源碼(黑客帝國文字下落效果)
這篇文章主要介紹了HTML+JS實現(xiàn)“代碼雨”效果源碼類似黑客帝國文字下落效果,需要的朋友可以參考下2020-03-03